Oct 30, 20266 min read

AWS Lambda vs Fargate: Which Should Run Your Backend

How Lambda functions and Fargate containers differ on time limits, scaling, database connections, cost and local development, for an API with background work.

AWS Lambda and AWS Fargate are the two ways to run backend code on AWS without managing servers, and they suit different shapes of work. Lambda runs a function per event, scales to zero and bills by the millisecond, with a hard 15-minute limit. Fargate runs containers that stay up, so they can hold database pools and long jobs, but a service with one task keeps billing all night.

The choice gets harder once a backend has more than one kind of work. An HTTP API, a queue worker and a nightly job pull in different directions, and RDS connections behave very differently on each. This guide compares the two on those points and shows how Encore runs an API and its worker on Fargate from application code.

Lambda vs Fargate at a glance

EncoreAWS LambdaAWS Fargate
Unit of deploymentTypeScript or Go servicesA function per handlerA task definition per service
Time limitNone per request15 minutes per invocationNone
Idle costFargate tasks keep runningNothing when idleEach running task's vCPU and memory
ScalingFargate defaults per environmentPer request, concurrency limitsTarget tracking on CPU, memory or requests
Postgres connectionsPooled per service, RDS created for youOne per concurrent invocation, RDS Proxy advisedNormal pool per task
QueuesTopics and subscriptions in codeEvent source mappingsYour own consumer loop
Local developmentencore run with local Postgres and Pub/SubSAM or emulatorsDocker Compose

Each option is covered below, starting with Encore.

Running services and workers on Fargate with Encore

Encore combines an open source infrastructure SDK for TypeScript and Go with a platform that provisions and deploys into your own AWS or GCP account. On AWS, services run on Fargate behind an Application Load Balancer in private subnets, Pub/Sub becomes SNS topics with SQS queues and dead-letter queues, and Encore provisions an IAM role for each service.

Application code passes through Encore and infrastructure guardrails to resources provisioned in your own AWS or GCP account.
Encore provisions the infrastructure your application needs in your own AWS or GCP account.

On Lambda, an API that hands slow work to a queue is two functions, an SQS queue, an event source mapping and the IAM between them. With Encore the API and the worker sit in the same codebase:

// exports/exports.ts import { api } from "encore.dev/api"; import { Topic, Subscription } from "encore.dev/pubsub"; import log from "encore.dev/log"; interface ExportRequested { exportId: string; accountId: string; } // SNS and SQS on AWS, Pub/Sub on GCP, an in-process emulator under encore run. export const exportRequested = new Topic<ExportRequested>("export-requested", { deliveryGuarantee: "at-least-once", }); export const requestExport = api( { expose: true, method: "POST", path: "/exports" }, async ({ accountId }: { accountId: string }): Promise<{ exportId: string }> => { const exportId = crypto.randomUUID(); await exportRequested.publish({ exportId, accountId }); return { exportId }; }, ); // Runs on Fargate, so a large export is not cut off at 15 minutes. const _ = new Subscription(exportRequested, "build-export", { handler: async (e) => { log.info("building export", { exportId: e.exportId, accountId: e.accountId }); // Generate the file and store it. Make this safe to run twice for the same exportId. }, // The default ack deadline is 30 seconds. Give long jobs more time before redelivery. ackDeadline: "30m", retryPolicy: { maxRetries: 5, minBackoff: "10s" }, });
Get started
brew install encoredev/tap/encore &&
encore app create
Copy

Run in your terminal to get started locally.

encore run starts the API and an in-process Pub/Sub locally, so a curl to /exports shows the message reaching the worker in the local trace view. On deploy, the topic becomes SNS with an SQS queue behind the subscription, failed messages land in a dead-letter queue after the retries, and the worker is not bound by Lambda's 15-minute limit. The ackDeadline setting controls how long a handler can hold a message before it is redelivered, and the Pub/Sub docs cover ordering, retries and concurrency.

An agent asked to "move exports to a background job" can make the whole change in TypeScript and check it locally.

AWS Lambda: functions per event

Lambda runs your code in response to events such as API Gateway requests, SQS messages or schedules, and you pay only for execution time. A function can run for at most 15 minutes and use up to 10,240 MB of memory, and AWS adds execution environments as concurrent requests arrive.

That model is ideal for spiky traffic and glue code. It becomes awkward for a stateful backend. Every concurrent invocation is its own environment, so 300 concurrent requests can open 300 Postgres connections, which is why AWS suggests RDS Proxy in front of RDS for Lambda workloads. Functions that reach a private database run in your VPC, cold starts add latency to the first request on a new environment, and long jobs have to be split into steps or handed to something else.

AWS Fargate: containers that stay running

Fargate runs ECS tasks or EKS pods without EC2 instances to manage. A service keeps a desired number of tasks running behind a load balancer, each with a normal connection pool, and requests or jobs can run as long as they need.

You pay per second for each task's vCPU and memory, per Fargate pricing, whether it is busy or not, and there is no scale to zero on incoming requests. The setup around the task is also yours: task definitions, the load balancer and target groups, autoscaling policies, and a consumer loop with visibility timeouts if a task reads from SQS.

Good to know

A common setup uses both, with Lambda for small event handlers and Fargate for the API and long-running workers. The split doubles the deploy paths and the IAM policies to maintain, and local development has to cover two runtime models.

How to choose

Pick Encore when your backend is a set of APIs, queue workers and scheduled jobs that should run on Fargate in your own AWS account, with SNS, SQS, RDS and IAM created from the code and the APIs and queue workers runnable locally. Scheduled jobs run only in cloud environments, not with encore run.

Pick Lambda for low or bursty traffic and event handlers that finish in seconds, where scaling to zero matters more than connection pooling. Pick Fargate directly when you need long-running services and already have the infrastructure code and pipeline to define them.

Frequently asked questions

When should I use Lambda instead of Fargate?

Use Lambda for event handlers and APIs with spiky or low traffic that finish well within 15 minutes, where paying per request and scaling to zero matter most. Use Fargate for services that run continuously, hold connections such as WebSockets or database pools, or do work that can take longer than 15 minutes.

Is Fargate cheaper than Lambda?

Utilization decides it. Lambda bills per millisecond of execution and costs nothing when idle, so low or bursty traffic is cheaper on Lambda. Fargate bills per second for the vCPU and memory of each running task, so a service that is busy most of the day is usually cheaper on Fargate.

How do I run an API and a queue worker on Fargate with Encore?

With Encore, you declare the API with api() and the worker as a Subscription on a Topic in TypeScript, then deploy to an AWS environment. Encore runs the services on Fargate behind an Application Load Balancer and creates the SNS topic and SQS queue, with an IAM role for each service.

Deploy to your cloud on AWS and Google Cloud
without managing infrastructure

Encore lets developers and agents define application infrastructure directly in code, then automatically provisions it from local development to production in your AWS or GCP account.

~/orders — claude
Claude Code
Claude Code v2.1.180Opus 5.5~/orders