Journal / Backend, APIs, and System Design

Backend, APIs, and System Design

Serverless vs Containers vs Bare Metal: A Cost and Flexibility Map

Compute models for web applications describe how application code is executed and billed. Serverless functions (AWS Lambda, Vercel Functions, Cloudflare Workers) execute code on demand and bill per invocation and execution time, with nothing running around the clock to manage. Containers (Docker on ECS, Kubernetes, Railway, Render) package application code with its runtime and run as processes that stay on continuously or scale automatically. Bare metal or VPS hosting runs application code on dedicated or virtual machines where the team manages the operating system and runtime environment.

What you need to know

  • Serverless is the cheaper option for spiky traffic or a low, steady baseline. It gets expensive at consistently high request rates with meaningful execution duration.
  • Containers provide predictable cost at consistent traffic levels and are appropriate for stateful connections, continuous workloads, and AI inference.
  • Bare metal or VPS is the most cost efficient choice for CPU and memory intensive continuous workloads, provided the team has the DevOps capacity to manage the infrastructure.
  • Cold start latency is a real tradeoff for serverless. Use provisioned concurrency or containers for latency sensitive, user facing operations.
  • The operational overhead increases from serverless to containers to bare metal. Match the compute model to the team's operational capacity.

The core argument

The compute model decision is inseparable from the team's operational capacity. Serverless provides the lowest operational overhead at the cost of flexibility and potentially higher cost at scale. Bare metal provides the highest flexibility and the lowest cost per unit of compute, at the cost of significant operational overhead. Containers sit in the middle: more flexibility than serverless, less operational overhead than bare metal.

The mistake is choosing a compute model based on performance or cost in isolation, without accounting for the operational capacity required to run it. A team of two engineers without a DevOps background running their application on bare metal spends a disproportionate fraction of their time on infrastructure management rather than product work. A team of 15 engineers with a dedicated DevOps function running everything on Lambda at high traffic volumes pays three times the container cost without a clear benefit to show for it.

The decision framework: start with what the team can operate reliably today, and migrate toward more cost efficient models as operational capacity grows. For most early stage SaaS products, a managed container platform (Railway, Render, or Fly.io) provides the right balance: more control than pure serverless, less operational overhead than self managed Kubernetes or bare metal. Migrate to AWS ECS or self managed infrastructure once the cost savings justify the operational investment.

Common mistakes

  1. Choosing serverless for a product that requires persistent connections. WebSocket based real time features, long polling, and streaming responses are difficult or impossible to implement correctly in serverless functions, which have execution time limits and no persistent process state. If the product requires real time bidirectional communication, containers with a persistent process are the appropriate compute model.

  2. Not modeling cold start impact on the user experience. Teams choosing serverless for user facing APIs without analyzing cold start frequency and impact may discover the problem only in production, when users report intermittent slowness. Use AWS X-Ray or Datadog Lambda tracing to measure cold start frequency and duration. If cold starts occur regularly in the user facing critical path, configure provisioned concurrency or migrate the affected functions to containers.

  3. Running databases on autoscaled containers without connection pooling. A serverless function that opens a new database connection for every invocation can exhaust the database's connection limit at high concurrency. Each Lambda invocation creates a new connection; 100 concurrent invocations create 100 connections. Use PgBouncer, RDS Proxy, or a database built with a connection model meant for serverless (PlanetScale, Neon) when running database connected code in serverless functions.

  4. Over provisioning bare metal for variable workloads. Bare metal servers stay on continuously; they do not scale down when traffic is low. Provisioning bare metal for peak traffic means paying for peak capacity all the time. Variable workloads (products with daily or weekly traffic cycles) should use containers that scale automatically, or serverless, not bare metal. Bare metal is efficient for workloads with consistently high and predictable resource utilization.

  5. Not accounting for egress costs in the compute model comparison. Cloud provider egress (data transferred out of the cloud) can be a significant cost line, especially for products that return large payloads or serve media. Egress costs are roughly similar across serverless, containers, and VMs on the same cloud provider. Switching to Hetzner reduces compute cost dramatically but does not reduce egress cost for European regions to the same extent.

Where to start

  1. Categorize workloads by traffic pattern and execution characteristics. List the main workload types in the product: user facing API requests (traffic pattern, average execution time, memory needs), background jobs (continuous vs triggered, execution duration), and heavy processing tasks (ML inference, document processing, report generation). Each category may warrant a different compute model.

  2. Compare the monthly cost of the current compute model against alternatives for the primary API workload. Pull the current monthly compute cost per request for the main API. Calculate the equivalent cost on Lambda (invocation cost plus execution time cost), on a container platform (hourly or monthly rate divided by expected request capacity), and on a Hetzner VPS (monthly instance cost divided by expected capacity). The comparison reveals whether the current model is the most cost effective one at current scale.

  3. Migrate one low risk workload to test operational requirements of the target model. Before migrating the main application, migrate one background job or side service. This pilot reveals the operational challenges of the new compute model in a low risk context and builds the team's experience before the main migration.

FAQ

Frequently asked

  • What are the cost characteristics of serverless at different traffic levels?
  • What operational overhead does each compute model require?
  • When do containers provide a better fit than serverless?
  • When does bare metal or a dedicated VPS produce better cost efficiency than managed compute?
  • How does cold start affect the serverless vs container decision?

Author

Closing note from the author

I keep these closing notes short on purpose. Yashveer Singh, founder of Yashveer Labs. The contact channel is Instagram. The proof is the portfolio. The standard is in the work. If we are aligned, you will know within five minutes of the first message.

Start the conversation See the work DM on Instagram