Serverless Computing: The Promise, the Reality, and the Bill

Serverless has been around long enough that it should be boring by now. Lambda launched in 2014. It's 2026. We should have figured this out.
And in some ways, we have. The tooling is better, the cold starts are shorter, the ecosystem is mature. But I still see teams picking serverless for the wrong reasons, getting surprised by the bill, and then migrating to containers six months later while pretending the whole thing never happened.
So here's where I think serverless actually stands -- what it's good at, where it falls apart, and why the billing model is the thing you should be thinking about before anything else.
There are servers. Obviously.
The name is bad. Everyone knows the name is bad. "Serverless" means you don't manage servers, not that servers don't exist. Your code runs on someone else's machines, provisioned on demand, scaled automatically, and billed per invocation. You don't SSH into anything. You don't patch anything. You don't think about capacity planning (in theory).
The mental model that works: serverless is a billing and operations abstraction. You write functions, deploy them, and pay for what runs. The cloud provider handles the rest. That's genuinely useful. It's just not magic.
Where serverless actually works well
I've had good results with serverless in a few specific patterns:
Event-driven workloads. Something happens (file uploaded, webhook received, message queued), a function processes it, done. No idle compute sitting around waiting. This is the sweet spot, and it has been since day one.
Spiky traffic. If your traffic goes from 10 requests per minute to 10,000 and back, serverless handles that without you doing anything. Try that with a fixed container fleet and you're either over-provisioned (wasting money) or under-provisioned (dropping requests).
API backends for moderate traffic. REST or GraphQL endpoints that handle a few hundred requests per second? Serverless works fine. Clean, simple, no infrastructure to babysit.
Scheduled jobs. Cron tasks that run for a few seconds or minutes. Way easier than maintaining a server that sits idle 23 hours a day just to run a nightly cleanup script.
The common thread: intermittent work. Functions that spin up, do a thing, and go away. If your workload fits that shape, serverless is probably the right call.
Cold starts: better but not gone
This is the thing people ask about first. The honest answer: cold starts in 2026 are much shorter than they were five years ago, but they still exist and they still matter for certain use cases.
AWS Lambda with Node.js or Python typically cold starts in 100-300ms. Java or .NET can be over a second, sometimes much more. Provisioned concurrency helps, but it also means you're paying for idle compute -- which defeats part of the point.
Cloudflare Workers basically don't have cold starts because they use V8 isolates instead of containers. The tradeoff is a more restricted runtime (no arbitrary Node.js APIs, limited CPU time).
Vercel Functions sit somewhere in between. They run on AWS infrastructure but Vercel has done work on reducing cold starts for Next.js and other frameworks. For most web workloads, you won't notice.
If you're building a real-time API where p99 latency matters, cold starts will bite you. If you're handling webhooks or background jobs, you probably won't care.
The bill
Here's where it gets interesting. Serverless pricing follows a curve that's great at the bottom and painful at the top.
At low volume, serverless is almost free. Lambda's free tier covers a million requests per month. If you're running a side project or an internal tool, you might literally pay nothing.
At moderate volume, it's competitive with containers. A few hundred thousand invocations per day, reasonable execution times -- the math works out roughly the same as a couple of small ECS tasks or a Kubernetes pod.
At high volume, it gets expensive fast. I've talked to teams running millions of invocations per day who switched to containers and cut their compute bill by 60-70%. When your functions are warm most of the time anyway, you're paying a premium for the auto-scaling you're barely using.
The unpredictable part is the middle. Your bill depends on invocation count, execution duration, and memory allocation -- three variables that interact in non-obvious ways. A function that runs for 200ms at 512MB costs twice as much at 1024MB, even if it finishes in 150ms. Sometimes increasing memory makes things cheaper because the function finishes faster. Sometimes it doesn't. You have to measure.
My rule of thumb: if your monthly compute bill would be under $500 on containers, serverless is probably cheaper or comparable. Above that, do the math carefully.
Vendor lock-in is real
Nobody talks about this at the start of a project. Everyone talks about it during the migration.
Lambda functions use AWS-specific triggers, IAM roles, API Gateway configurations, layer formats. Moving to Google Cloud Functions or Azure means rewriting not just the functions but the entire deployment and integration layer. Your business logic might be portable. Everything around it isn't.
The Serverless Framework and SST help somewhat -- they provide abstractions over provider-specific details. But the abstraction is leaky. You still end up depending on provider-specific features because that's where the value is.
My take: vendor lock-in is the cost of convenience. If you're a startup moving fast, it's probably worth it. If you're an enterprise planning to run this for a decade, factor the exit cost into your decision.
Serverless vs containers vs edge
These aren't competing options -- they solve different problems.
Serverless functions (Lambda, Vercel Functions): best for request/response workloads with variable traffic. No infrastructure management. Pay per use.
Containers (ECS, Cloud Run, Kubernetes): best for steady-state workloads, long-running processes, or anything that needs persistent connections. More control, more operational overhead.
Edge functions (Cloudflare Workers, Vercel Edge Functions): best for latency-sensitive, lightweight work -- auth checks, redirects, header manipulation, personalization. Limited runtime, limited execution time, but runs close to users.
Most production systems I've worked on use a mix. Edge for routing and auth, serverless for API endpoints and webhooks, containers for background workers and data pipelines. Pick the right tool for each piece.
Platform differences that matter in practice
AWS Lambda is the most flexible. Supports the most languages, has the richest ecosystem of triggers (SQS, SNS, DynamoDB streams, S3 events, API Gateway, ALB). Also the most complex to configure. If you're already in AWS, it's the default choice.
Vercel Functions are the easiest if you're building with Next.js or a similar framework. Deploy a route handler, it becomes a function. The DX is good. The tradeoff is less flexibility -- you're inside Vercel's deployment model, and advanced configurations require workarounds.
Cloudflare Workers have the best cold start story and run at the edge by default. The restriction is the V8 isolate model -- no filesystem, no native modules, limited memory. If your function fits those constraints, Workers are fast and cheap. If it doesn't, you're stuck.
State management: the hard part nobody warns you about
Functions are stateless. You knew that. What you might not have internalized is how much of your application is actually state.
User sessions, rate limiting, distributed locks, caching, connection pools -- all the things you'd normally handle in memory or with a local process now need an external service. Redis, DynamoDB, Upstash, Planetscale. Each one adds latency, cost, and a new failure mode.
Database connections are particularly annoying. Each function invocation might open a new connection. At scale, you exhaust your database's connection limit. Connection pooling services (like RDS Proxy or Neon's connection pooler) exist specifically because of this problem.
I've seen teams spend more time managing state around their serverless functions than they would have spent managing the servers they were trying to avoid. That's not always the wrong tradeoff -- but it's a tradeoff you should make deliberately.
What I actually recommend
Use serverless for the workloads it's good at. Event processing, webhooks, moderate-traffic APIs, scheduled jobs, prototype backends. Don't use it for everything just because it's trendy or because someone on your team read an article about going "fully serverless."
Check the bill monthly. Set up billing alerts before you deploy, not after the first invoice. The pricing model rewards you for being right about your traffic patterns and punishes you for being wrong.
Accept the vendor lock-in or mitigate it upfront. Wrapping everything in abstractions "just in case" adds complexity now for a migration that might never happen. But if you're genuinely multi-cloud, invest in the abstraction layer early.
And don't forget about the state problem. If your architecture needs shared state across function invocations -- and most non-trivial ones do -- budget time and money for that from the beginning. It's the part that's easy to underestimate and hard to fix later.
Serverless is a good tool. Like most good tools, it works best when you use it for what it's actually designed for.


