"Should we go serverless or run containers?" is one of the most consequential architecture decisions a team makes early, and one of the most frequently made for the wrong reasons. Teams pick serverless because it's trendy, then get surprised by cold starts and a bill that scales with traffic spikes. Or they reach for Kubernetes because it feels "real," then spend more time operating clusters than shipping features. The right answer depends on your workload shape, your cost profile, and — more than anything — the size and experience of your team.
This guide breaks down what each model actually is, where the real tradeoffs live, and a decision framework you can apply to your own stack.
What They Actually Are
Serverless (Functions-as-a-Service)
Serverless means you deploy individual functions — AWS Lambda, Google Cloud Functions, Azure Functions, Vercel Functions — and the platform handles provisioning, scaling, and teardown entirely. You don't manage servers, operating systems, or scaling policies. The platform spins up an execution environment when a request arrives and tears it down when traffic stops. You're billed per invocation and per millisecond of compute used.
Containers
Containers package your application and its dependencies into a portable image (Docker) that runs on orchestration platforms like Kubernetes, AWS ECS, Google Cloud Run, or Fly.io. You define how many instances run, how they scale, and how they network together. Containers run continuously (or scale to zero with platforms like Cloud Run), giving you full control over the runtime, long-lived connections, and background processing.
The simplest mental model: serverless is renting a seat only while you're sitting in it; containers are renting the room. One optimizes for not paying when idle; the other optimizes for control and predictable behavior under load.
The Cost Models Are Fundamentally Different
This is where teams get surprised, so it's worth being precise.
- Serverless is per-invocation. You pay for each request and the compute it consumes. At low or spiky traffic, this is dramatically cheaper — an internal tool that runs 10,000 times a month might cost cents. But the cost scales linearly (and sometimes punishingly) with volume. A high-traffic API doing billions of invocations can cost far more on Lambda than the equivalent containers.
- Containers are always-on (or near it). You pay for provisioned capacity whether or not requests are flowing. At steady, high traffic this is efficient — you're using what you pay for. At low or bursty traffic, you're paying for idle instances. Autoscaling and scale-to-zero platforms (Cloud Run, Fargate) soften this, but you still pay for warm capacity and a baseline.
The crossover point matters: serverless wins on cost for unpredictable, low-to-medium, or spiky workloads. Containers win once you have sustained, high-volume traffic where always-on capacity is cheaper than paying per request.
Cold Starts
The defining drawback of serverless is the cold start: when no warm execution environment exists, the platform must initialize one before handling the request. Depending on runtime and package size, that's anywhere from ~100ms (lightweight Node/Go) to several seconds (large Java or heavy dependency trees).
For background jobs and async processing, cold starts are irrelevant. For user-facing APIs with latency budgets, they're a real problem. Mitigations exist — provisioned concurrency (keeping functions warm), smaller bundles, lighter runtimes — but provisioned concurrency erodes the very cost advantage that made serverless attractive. Containers don't have cold starts in the same way; a running container responds immediately, though scale-to-zero container platforms reintroduce a milder version of the problem.
Scaling Behavior
Serverless scales automatically and near-instantly to thousands of concurrent executions with zero configuration — this is its superpower. A sudden traffic spike is absorbed without you touching anything. The catch: downstream dependencies (databases, third-party APIs) may not survive 5,000 simultaneous function invocations hammering them. Connection pooling becomes a genuine architectural challenge.
Containers scale based on rules you define — CPU, memory, request count, custom metrics. This is slower to react to spikes (instances take seconds to minutes to start) but gives you control to protect downstream systems and avoid surprise scaling events. You decide the ceiling.
Vendor Lock-In and Operational Overhead
Serverless ties you more tightly to a provider. Lambda's event model, IAM integration, and ecosystem assumptions don't port cleanly to another cloud. Containers are portable by design — a Docker image runs anywhere — though once you adopt managed orchestration and cloud-specific services, you reintroduce lock-in through the back door.
Operationally, the equation is clearest here. Serverless removes nearly all infrastructure management: no patching, no capacity planning, no cluster upgrades. Containers — especially self-managed Kubernetes — carry significant operational weight: cluster maintenance, networking, security patching, observability. Managed container platforms (Cloud Run, Fargate, App Runner) split the difference, removing most cluster operations while keeping the container model.
A Decision Framework
Rather than picking by trend, walk through these questions:
- What's your traffic shape? Spiky, unpredictable, or low-volume → serverless. Sustained, high-volume → containers.
- How latency-sensitive are you? Strict user-facing latency budgets → containers (or serverless with provisioned concurrency). Async/background → serverless.
- How big is your team? Small team, few ops people → serverless or managed containers. You don't have the headcount to run Kubernetes well.
- Do you need long-running processes? WebSockets, streaming, long jobs, persistent connections → containers. Most function platforms cap execution time (often 15 minutes) and don't suit persistent connections.
- What's your cost ceiling? Model both at your projected scale. Don't assume; run the numbers at 10x current traffic.
Hybrid Approaches Are Often the Right Answer
The framing as a binary choice is misleading. Mature architectures routinely mix both:
- Containers for the steady-state core API where always-on capacity is cost-efficient and latency matters.
- Serverless for spiky, event-driven work — image processing, webhook handlers, scheduled jobs, file uploads — where paying only on use is the win.
- Serverless for the unpredictable edges, containers for the predictable center.
This lets each workload run on the model that fits it. The discipline is keeping the seams clean — a shared data layer and well-defined contracts — so the two halves don't become two systems to operate.
When to Use Each
Reach for serverless when: you're early-stage with unpredictable traffic, building event-driven or async workloads, running internal tools, want minimal operational overhead, or have a small team that needs to ship without managing infrastructure.
Reach for containers when: you have sustained high traffic, strict latency requirements, long-running or stateful processes, need full runtime control, or have the operational maturity to run orchestration well.
Frequently Asked Questions
Is serverless always cheaper than containers?
No. Serverless is cheaper at low, spiky, or unpredictable traffic because you pay nothing when idle. At sustained high volume, always-on containers are typically cheaper because per-invocation pricing scales linearly with requests. Always model both at your projected scale before deciding.
Do cold starts make serverless unusable for APIs?
Not unusable, but they're a real consideration for latency-sensitive, user-facing endpoints. With lightweight runtimes (Node, Go) cold starts are often around 100ms, and provisioned concurrency can eliminate them — at the cost of reducing serverless's cost advantage. For async and background work, cold starts don't matter at all.
Can I use both serverless and containers together?
Yes, and many production systems do. A common pattern is containers for the steady-state core API and serverless for spiky, event-driven tasks like webhooks, image processing, and scheduled jobs. The key is keeping clean contracts and a shared data layer so the two halves stay one coherent system.
Does serverless mean no servers at all?
No — servers still exist; you just don't manage them. The provider handles provisioning, scaling, patching, and teardown. "Serverless" refers to the absence of server management responsibility on your side, not the absence of servers.
Open Door Digital helps engineering teams make architecture decisions like this with cost modeling, workload analysis, and migration support tailored to your traffic and team. Talk to our team about your infrastructure roadmap.
Related reading: AWS vs Azure vs GCP, CI/CD Pipeline Guide, and Cloud Migration Guide.