Serverless vs Virtual Machines: A Practical Comparison

Serverless is not “no servers”; it is “not your servers, and billed per invocation”. That change in the billing unit is what makes it excellent for some workloads and unsuitable for others.

The billing unit is the whole story

A virtual machine bills for time it exists, whether or not it is doing anything. A function bills for execution — roughly invocations multiplied by duration multiplied by allocated memory.

Consequences:

  • A workload idle 95% of the time is dramatically cheaper serverless.
  • A workload busy continuously is usually cheaper on a machine, sometimes by a wide margin.
  • The crossover point is a real calculation, not a preference, and it belongs in the cost estimate.

Where serverless is clearly better

  • Event handlers. React to an upload, a queue message, a schedule. The work is short, the arrival rate is unpredictable, and there is nothing to keep warm.
  • Spiky, low-average traffic. Scaling from zero to many concurrent executions and back is the platform’s job.
  • Glue between services. Small transformations that would otherwise need a server to live on.
  • Anything you would otherwise run as a cron job on a machine that exists only for that.

Where a virtual machine is clearly better

  • Long-running processes. Function platforms impose an execution time limit; work that exceeds it must be restructured.
  • Steady, predictable load. Continuous traffic on a machine you already pay for.
  • Anything holding a persistent connection — websockets, long polling, database connection pools.
  • Workloads with unusual dependencies — large binaries, GPUs, specific kernel features.
  • Latency-sensitive paths where a cold start is unacceptable and traffic is too sparse to keep instances warm.

Cold starts, honestly

The first invocation after an idle period pays initialisation cost. How much depends on the runtime, the size of the deployment package and whether a network or database connection has to be established. It is a real constraint for user-facing latency and a non-issue for background work.

Mitigations exist — provisioned concurrency, smaller packages, lighter runtimes — and provisioned concurrency in particular reintroduces a fixed cost, which is worth noticing because it partially undoes the reason for choosing serverless.

State and connections

Functions are stateless and may run at high concurrency, which interacts badly with databases that have a bounded connection count. The standard answers are a connection proxy or pooler in front of the database, or a data store designed for HTTP-scale access. Discovering this under load is a common and avoidable outage.

Most systems use both

A typical shape: the application on containers or virtual machines behind a load balancer, with functions handling uploads, scheduled work, webhooks and notifications. That is not indecision — it is matching the billing unit to the traffic shape of each component.

Where to go next

Questions

Frequently asked

Is serverless cheaper than a virtual machine?

For workloads that are idle most of the time, usually yes. For continuous load it is often more expensive, because you pay per invocation rather than for a machine you are keeping busy.

What is a cold start?

The initialisation cost paid on the first invocation after an idle period. It matters for user-facing latency on sparse traffic and is generally irrelevant for background work.

Can serverless functions talk to a normal database?

Yes, but high concurrency can exhaust the database's connection limit. A connection pooler or proxy in front of the database is the usual answer.

Shopping Cart
Scroll to Top