Back to Blog
· 12 min read · EN

Lambda vs ECS Fargate vs App Runner: Which AWS Compute to Choose

A detailed comparison of AWS Lambda, ECS Fargate, and App Runner covering cold starts, pricing, scaling, and when to use each for your workload.

CloudArchitecture #aws#lambda#fargate#app-runner#serverless#containers
Lambda vs ECS Fargate vs App Runner: Which AWS Compute to Choose

“Should I use Lambda or containers?” is the question I get asked most often during technical consultations. And my answer is always: “It depends on your workload profile.” Which is unsatisfying, I know. So let me give you the complete framework I use to decide.

After running 40+ production systems across all three compute options, I have strong opinions about when each shines and when each hurts. This is not a theoretical comparison. These are patterns from real projects with real cost data.

Quick Comparison Table

Before we dive deep, here is the executive summary:

FeatureLambdaECS FargateApp Runner
Cold start100ms-2sNoneNone
Max request timeout15 minUnlimited120s
Min billing granularity1msPer-secondPer-second
Auto-scaling speedInstant1-3 min30s-2 min
Max concurrent1000 defaultService limits200 default
VPC requiredOptionalYesOptional
Container supportYesYesYes
WebSocket supportVia API GWNativeNo
gRPC supportNoYesNo
Minimum cost at zero traffic$0~$10/mo$0 with pause
Operational complexityLowMediumVery Low
Customization levelMediumHighLow

This table tells one story. But the real decision happens when you map your specific workload against these constraints.

Lambda Deep Dive

Lambda is AWS’s function-as-a-service offering. You upload code, define a trigger, and AWS handles everything else. No servers, no containers to manage, no patching.

When Lambda Shines

Event-driven workloads. Processing S3 uploads, SQS messages, DynamoDB streams, SNS notifications. Lambda was built for this. You pay nothing when no events arrive.

Bursty, unpredictable traffic. If your API goes from 10 requests/minute to 10,000 requests/minute without warning, Lambda handles it without pre-provisioning.

Scheduled tasks. CRON jobs that run for under 15 minutes. No need to keep a server running 24/7 for a task that executes 3 times a day.

Glue code and integrations. Webhook receivers, data transformations, API proxies. Small functions that connect systems.

Lambda Pricing Model

Lambda charges on two dimensions:

  • Requests: $0.20 per 1 million invocations
  • Duration: $0.0000166667 per GB-second

Example calculation for a REST API:

50,000 requests/day = 1.5M requests/month
Average duration: 200ms at 512MB memory

Request cost: 1.5M * $0.20/1M = $0.30
Duration cost: 1.5M * 0.2s * 0.5GB * $0.0000166667 = $2.50
Total: ~$2.80/month

At low traffic, Lambda is absurdly cheap. But watch what happens when we scale up:

5,000,000 requests/day = 150M requests/month
Average duration: 200ms at 512MB memory

Request cost: 150M * $0.20/1M = $30
Duration cost: 150M * 0.2s * 0.5GB * $0.0000166667 = $250
Total: ~$280/month

At 5M requests/day, you are paying $280/month. A Fargate service handling the same load would cost roughly $120/month. The crossover point depends on your duration and memory, but it typically happens between 1-5M daily requests.

Lambda Weaknesses

Cold starts are real. First invocation after idle time adds latency:

  • Node.js/Python: 100-300ms
  • Java/C#: 500ms-2s
  • With VPC: Add 200-500ms

Provisioned concurrency solves this but costs money even when idle, defeating much of the serverless value proposition.

15-minute timeout. Any process that takes longer simply cannot run on Lambda. Video processing, large data exports, and complex ML inference often hit this wall.

No persistent connections. WebSockets, gRPC streaming, and long-polling are not possible. API Gateway WebSocket support exists but adds complexity and cost.

Stateless by design. No local file system persistence between invocations. No in-memory caching across requests. Every invocation starts fresh.

ECS Fargate Deep Dive

Fargate is container-as-a-service. You define your container image, specify CPU and memory, and AWS runs it without any EC2 instances to manage. I wrote extensively about why I prefer Fargate over Kubernetes for small teams.

When Fargate Shines

Long-running APIs with consistent traffic. Your core backend API that handles user requests all day. Fargate gives you predictable performance with no cold starts.

WebSocket and gRPC services. Persistent connections work natively. No workarounds needed.

Workloads needing sub-50ms latency. No cold start penalty. Your container is always warm and ready.

Applications with in-memory state. Connection pools, local caches, loaded ML models. These persist across requests.

Batch processing exceeding 15 minutes. No timeout limits. Run as long as you need.

Fargate Pricing Model

Fargate charges per-second for allocated CPU and memory:

  • CPU: $0.04048 per vCPU per hour
  • Memory: $0.004445 per GB per hour

Example for a typical API service:

1 service: 0.5 vCPU, 1GB memory, running 24/7

CPU: 0.5 * $0.04048 * 730 hours = $14.78/month
Memory: 1 * $0.004445 * 730 hours = $3.24/month
Total per task: ~$18/month

With 2 tasks for availability: ~$36/month

For the same 50K requests/day workload from the Lambda example, a single Fargate task at 0.25 vCPU can handle it easily, costing around $12/month in compute alone. Add ALB at $22/month and you are at $34/month total. Cheaper than Lambda at scale, more expensive at low traffic.

Fargate Weaknesses

You pay for idle time. At 3 AM when traffic drops to zero, your containers are still running and billing. Auto-scaling helps but you always need minimum 1 task running.

Scaling is not instant. New tasks take 1-3 minutes to provision. During traffic spikes, you need pre-provisioned capacity or accept brief degradation.

More operational overhead than Lambda. Health checks, task definitions, service configuration, ALB setup, security groups. Not difficult, but more moving parts.

NAT Gateway costs. Private subnets need NAT Gateway for outbound internet access. That is $32/month base cost plus data processing charges. A sneaky expense that catches people off guard.

App Runner: The Simpler Alternative

App Runner is AWS’s attempt at “just give me a URL for my container.” Push your code or container image, configure basic settings, and get a running service with auto-scaling, TLS, and load balancing built in.

When App Runner Shines

Internal tools and admin dashboards. Services that do not need maximum performance or customization. Your admin panel, internal API, or staging environment.

Teams without AWS expertise. If nobody on the team knows ECS, App Runner gets you running in minutes instead of hours.

Simple HTTP services. Request-response workloads that do not need WebSockets, gRPC, or complex networking.

Prototype and MVP deployments. Get something live fast without investing in infrastructure design.

App Runner Limitations

120-second request timeout. Cannot handle long-running requests or streaming responses.

No WebSocket or gRPC support. HTTP/HTTPS only.

Limited networking control. VPC connectivity is possible but restricted. No fine-grained security group control.

Fewer scaling options. Basic auto-scaling based on concurrent requests or CPU. No custom metrics.

No task placement control. Cannot specify AZ distribution or instance spread.

Higher per-request cost at scale. The simplicity premium means you pay more per compute unit compared to Fargate.

App Runner Pricing

  • Provisioned instances: Same rates as Fargate compute
  • Pause-to-zero: Services can scale to zero with no charge

The scaling model is the differentiator. App Runner can automatically pause when there is no traffic, making it free during idle periods, something Fargate cannot do natively.

Performance Benchmarks

Real numbers from load testing identical Go APIs deployed across all three platforms:

Cold Start Latency (P95)

PlatformCold Start P95Warm Response P50Warm Response P99
Lambda (Go)180ms8ms45ms
Lambda (Node.js)250ms12ms65ms
Lambda (Java)1.2s15ms80ms
FargateN/A (always warm)5ms25ms
App RunnerN/A (always warm)7ms35ms

Sustained Throughput (single instance equivalent)

PlatformMax RPSP99 Latency at 80% Load
Lambda (1000 concurrent)~500045ms
Fargate (1 vCPU, 2GB)~300025ms
App Runner (1 vCPU, 2GB)~250035ms

Lambda wins on raw throughput because each invocation gets its own execution environment. But the latency consistency goes to Fargate.

Cost Analysis for Three Workload Profiles

Profile 1: Bursty API (Webhook receiver)

Traffic pattern: 100 requests/hour normally, spikes to 10,000 requests/minute during business events. Average 50K requests/day.

PlatformMonthly CostNotes
Lambda$3-5Near-perfect fit. Pay only during spikes
Fargate$36-50Over-provisioned most of the time
App Runner$15-25Good with pause-to-zero between spikes

Winner: Lambda. This is exactly what serverless was designed for.

Profile 2: Steady Backend API

Traffic pattern: Consistent 200-500 RPS throughout business hours, dropping to 50 RPS at night. Average 20M requests/day.

PlatformMonthly CostNotes
Lambda$180-250Per-invocation cost adds up
Fargate (2 tasks)$72-100Most cost-effective at this load
App Runner$90-120Simpler but slightly more expensive

Winner: Fargate. Consistent load means container efficiency pays off.

Profile 3: Scheduled Jobs

Traffic pattern: Runs 4 times daily, processes data for 5-10 minutes each run.

PlatformMonthly CostNotes
Lambda$0.50-2Minimal cost, only runs when needed
Fargate (Scheduled Task)$2-5Good, but minimum 1-min billing
App RunnerN/ANot designed for batch workloads

Winner: Lambda. Scheduled tasks are Lambda’s bread and butter.

Decision Flowchart

Follow this text-based decision tree:

START: What is your primary workload type?

├─ Event-driven (webhooks, queue processing, S3 triggers)
│  └─ → Lambda

├─ HTTP API
│  ├─ Needs WebSockets or gRPC?
│  │  └─ Yes → Fargate
│  │
│  ├─ Traffic pattern?
│  │  ├─ Bursty/unpredictable → Lambda + API Gateway
│  │  ├─ Steady/predictable → Fargate
│  │  └─ Low with idle periods → App Runner
│  │
│  ├─ Latency requirement?
│  │  ├─ Sub-50ms P99 required → Fargate
│  │  └─ 100ms+ acceptable → Lambda or App Runner
│  │
│  └─ Team AWS experience?
│     ├─ None → App Runner
│     ├─ Some → Fargate
│     └─ Deep → Fargate (or Lambda for specific workloads)

├─ Batch processing
│  ├─ Under 15 minutes? → Lambda
│  └─ Over 15 minutes? → Fargate (ECS Scheduled Task)

└─ Background worker (queue consumer)
   ├─ Sporadic messages? → Lambda (SQS trigger)
   └─ Continuous stream? → Fargate

Migration Paths Between Platforms

Lambda to Fargate

The most common migration I help clients with. Typical triggers:

  • Cold starts causing user complaints
  • Hitting concurrency limits
  • Monthly bill exceeding Fargate equivalent
  • Need for WebSocket support

Migration approach:

// Your Lambda handler
func HandleRequest(ctx context.Context, event events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
    // Business logic here
}

// Becomes a standard HTTP handler for Fargate
func HandleRequest(w http.ResponseWriter, r *http.Request) {
    // Same business logic, different wrapper
}

The business logic stays the same. You are swapping the invocation wrapper and adding an HTTP server. Typical migration takes 1-2 days for a single service.

Fargate to App Runner

Simpler than you might think. If your service is a straightforward HTTP API without complex networking needs:

  1. Push your existing Docker image to ECR
  2. Create App Runner service pointing to that image
  3. Configure auto-scaling rules
  4. Update DNS

The catch: you lose fine-grained VPC control, custom health check paths beyond HTTP 200, and task placement strategies.

App Runner to Fargate

When you outgrow App Runner’s limitations:

  1. Create ECS cluster and service definition
  2. Set up ALB with health checks
  3. Configure auto-scaling policies
  4. Set up VPC networking
  5. Migrate DNS

More work, but it is a one-time investment that gives you full control.

When to Combine Them: The Hybrid Approach

Most production systems I build end up using multiple compute options. This is the hybrid pattern from my architecture guide:

Hybrid Architecture: Lambda + Fargate

Core API on Fargate: The service users interact with directly. Needs to be fast, reliable, always available.

Event processors on Lambda: Webhook handlers, SQS consumers, S3 event processors. Bursty and event-driven by nature.

Internal tools on App Runner: Admin dashboards, internal APIs, developer tools. Do not need maximum performance.

Scheduled tasks on Lambda: Daily reports, data cleanup, sync jobs. Run briefly and infrequently.

Example architecture for an e-commerce platform:

User traffic


[ALB] ──→ [Fargate: Product API]     ← Core API

              ├──→ [SQS] ──→ [Lambda: Order Processing]
              ├──→ [S3]  ──→ [Lambda: Image Resizing]
              └──→ [SNS] ──→ [Lambda: Notification Sender]

[EventBridge] ──→ [Lambda: Daily Report Generator]
[CloudWatch]  ──→ [Lambda: Cleanup Stale Sessions]

Admin users ──→ [App Runner: Admin Dashboard]

Each component uses the compute option that best matches its workload profile. This is not over-engineering. This is right-sizing.

Practical Recommendations

Based on my experience across dozens of projects:

If you are just starting out: Begin with Lambda. Zero upfront cost, zero infrastructure to manage. Migrate when you hit constraints, not before.

If you have a proven product with steady traffic: Move your hot path to Fargate. Keep everything else on Lambda. The cost savings and performance improvements are immediate.

If you want simplicity above all: App Runner for HTTP services, Lambda for everything else. Less control, less headache.

If you are running DevOps for a small team: The hybrid approach gives you the best cost-to-performance ratio without requiring deep AWS expertise for every component.

The worst decision is no decision. Pick one, ship your product, and optimize later when you have real usage data. I have seen too many teams spend weeks debating Lambda vs Fargate for a product that does not have users yet.

Start simple. Measure. Then optimize.

Need help choosing the right compute strategy for your specific workload? I offer DevOps support where we can analyze your traffic patterns and design an architecture that balances cost, performance, and operational simplicity.