Writing / 2020
Serverless vs Containers: Where the Math Stops Working
Lambda vs Fargate at different traffic levels, with mid-2020 prices: where serverless wins, where containers win, and where the cost crossover sits.
Serverless wins at low, bursty traffic. Containers win at sustained load. The crossover happens sooner than most people think. I’ve run workloads on both sides of that line and the difference in cost can be 3-5x if you pick wrong.
Everyone’s doing serverless now. Every conference talk. Every blog post. Every startup pitch deck mentions Lambda like it’s a personality trait.
I get it. At my own startup I build cloud infrastructure tooling, and serverless comes up in almost every conversation with its early users. Half the time it’s the right call. The other half, someone read a blog post and now their entire API runs on Lambda with 400ms cold starts and a monthly bill that makes no sense.
Side by side
People treat serverless vs containers like a religious debate. It’s arithmetic.
| Factor | Serverless (Lambda) | Containers (ECS/Fargate) |
|---|---|---|
| Traffic < 100K req/day | Cheap. Often free tier. | Overkill. Paying for idle. |
| Traffic 100K-1M req/day | Still reasonable. Watch concurrency. | Starting to make sense. |
| Traffic > 1M req/day, steady | Expensive. Very expensive. | Clear winner on cost. |
| Bursty (0 to 10K in seconds) | Handles it natively. | Needs autoscaling config. Lag. |
| Cold start tolerance | 200-800ms typical (JVM: seconds) | Zero. Already running. |
| Max execution time | 15 minutes hard cap | No limit |
| Connection pooling | Painful. Each instance = new connection. | Normal. Pool lives with the process. |
| Deployment complexity | Low per function. High at 50+ functions. | Medium, consistent. |
| Debugging in production | Distributed tracing or suffer | Logs are normal. Run the same image locally. |
That last row matters more than people admit.
Where serverless wins
I’ll give credit where it’s due, and I’ve been doing that since 2016 . For certain workloads, serverless is unbeatable.
Event processing. S3 upload triggers a function, function processes the file, done. No server sitting around waiting. This is the original Lambda use case and it’s still the best one. I use this pattern at my infrastructure startup to process infrastructure snapshots.
Webhooks and integrations. Glue code between services. Receives a payload, transforms it, passes it along. Runs maybe 200ms. Happens a few thousand times a day. Perfect fit. Running a container for this is like hiring a full-time employee to check the mailbox.
Cron jobs that run under 15 minutes. Cleanup tasks, report generation, health checks. A Lambda on a CloudWatch schedule is simpler than managing a cron server or scheduling containers.
Truly unpredictable traffic. If you can’t forecast whether you’ll get 10 requests or 10,000 in the next hour, serverless handles that gracefully. Containers need lead time to scale.
Where serverless costs you
This is the part that gets me uninvited from serverless meetups.
Sustained API traffic. If your API handles steady traffic (say 500+ requests per second, consistently), you’re paying a premium for Lambda that buys you nothing. The per-invocation cost adds up fast. I’ve seen teams cut their compute bill by 60-70% by moving a stable API from Lambda to Fargate. Not a theoretical number. Actual invoices.
Anything that needs database connections. This one drives me crazy. Lambda spins up instances independently. Each one opens its own database connection. You go from 10 concurrent executions to 500 during a traffic spike and suddenly your Postgres is drowning in connections. Yes, RDS Proxy is in preview now. It helps. It’s also another managed service you’re paying for to solve a problem containers don’t have.
Latency-sensitive paths. Cold starts. I know, provisioned concurrency exists. But provisioned concurrency is just… running a container with extra steps. You’re paying to keep Lambda instances warm. At that point, what are you even doing?
Complex request processing. If your function needs to do three API calls, a database write, and a cache update, that 200ms function becomes 800ms. You’re paying for all that wall-clock time. A container doing the same work with persistent connections and warm caches does it in 150ms.
Cost at two traffic levels
Rough numbers for a simple API endpoint, US East, mid-2020 pricing:
1 million requests/day, 200ms average duration, 256MB memory:
- Lambda behind API Gateway (REST API): ~$135/month. Lambda itself is only about $30 of that (invocations plus duration). The rest is API Gateway at $3.50 per million requests.
- Fargate (2 tasks, 0.5 vCPU, 1GB) behind a load balancer: ~$55/month
That’s about 2.5x. The new API Gateway HTTP APIs, at $1 per million requests, narrow the gap at this volume. At 5 million requests/day with the same profile, it widens again.
10,000 requests/day, bursty, same specs:
- Lambda behind API Gateway: under $2/month
- Fargate (1 task minimum, plus load balancer): ~$35/month
Flipped completely. Serverless is more than 10x cheaper at low volume.
The crossover point for a typical web API sits somewhere around 200K-500K requests per day, depending on duration, memory, and which API Gateway you use. Below that, serverless. Above that, containers. Measure your own workload, but it’s a reasonable starting point. Your cloud bill is a design document , and this is one of the numbers in it.
Lock-in at 50 functions
At 50+ Lambda functions with API Gateway, Step Functions, SQS triggers, DynamoDB streams, and EventBridge rules, you haven’t built an application. You’ve built an AWS application. Every piece of business logic is coupled to a specific AWS service.
Containers running your own code with standard libraries? Move them to GCP, Azure, your own hardware, whatever. The portability isn’t theoretical. I’ve done it.
I see this regularly. When a team wants to optimize or migrate, the ones running serverless-heavy architectures have a much harder time. Not impossible. Just harder and more expensive to change.
What I recommend
Stop asking “should we use serverless?” and start asking “what does the traffic look like for this specific endpoint?”
- Bursty, low-volume, event-driven? Lambda. Don’t overthink it.
- Steady traffic above a few hundred requests per second? Containers.
- Mixed? Use both. Nobody said you have to pick one.
The teams that do this well use serverless where the math works and containers where it doesn’t. No ideology. Just invoices.