Serverless vs Always-On: Working Out Which One Costs You Less

The answer is not a preference, it is a break-even calculation. Here is how to run the numbers for your own workload.

Hafeez BaigHafeez BaigMay 5, 20269 min read

Introduction

The serverless versus always-on argument is usually conducted as a matter of taste. One side says you should never pay for idle machines. The other says you should never let a cloud provider bill you per request. Both positions are stated as principles, and principles are hard to check.

The question has an answer, and the answer is arithmetic. Two pricing models produce two cost curves. Those curves cross somewhere. Your job is to work out where, and which side of that crossing point your workload sits on.

This post sets out the method. It deliberately quotes no prices, because provider rates change and any number written here would be wrong before you read it. Everything is expressed in symbols. You supply the current published rates from your own provider's pricing page.

1. The Two Pricing Shapes

Almost every hosting option is one of two shapes underneath the marketing.

Pay per hour, always-on. You reserve a machine. It has a fixed amount of CPU and memory. You pay for every hour it exists, whether it handles a million requests or none. A virtual machine, a container running continuously, a managed instance: all the same shape. Your cost is a flat line. It does not care about traffic.

Pay per request and duration, serverless. You upload code. The provider runs it when something calls it and charges you twice: a small fee for each invocation, meaning each individual time your function is triggered, and a fee for compute duration, meaning how long the function ran multiplied by how much memory you allocated to it. When nothing calls it, you pay nothing. Your cost is a line that rises from near zero in proportion to traffic.

That is the whole structure. A flat line and a sloped line. Two lines on the same axes cross exactly once. Everything else in this post is a refinement of where.

2. Traffic Shape Decides, Not Traffic Volume

The instinct is to say serverless is for small things and always-on is for big things. That is not quite right. The deciding factor is duty cycle: the proportion of time your machine would actually be doing work.

Consider two services that handle the same number of requests per month.

The first is an internal reporting tool, hammered for twenty minutes each morning and silent the rest of the day. On an always-on instance you buy 720 hours a month and use roughly 10 of them. Idle time is almost all of what you bought.

The second is a public API with steady traffic through the day. The instance sits at 70 percent CPU more or less permanently. Every hour you pay for is an hour of work. There is very little waste to eliminate.

Same volume, opposite conclusions. Serverless wins the first because it charges you nothing for the silence. Always-on wins the second because a reserved machine at high utilisation is one of the cheapest ways to buy compute, and serverless charges a premium for not having to think about capacity.

The general rule follows from this:

Serverless wins on spiky, unpredictable, or low duty cycle workloads. Always-on wins once utilisation is high and steady, because you are paying for a machine you are actually using.

3. The Break-Even, Written Symbolically

Define your variables. Every one of these is something you can measure or look up.

SymbolMeaningWhere it comes from
RRequests per monthYour analytics or load balancer logs
DAverage compute time per request, in secondsYour latency metrics, server side only
MMemory allocated per function, in GBYour configuration choice
PiPrice per invocationProvider's current pricing page
PdPrice per GB-second of durationProvider's current pricing page
HHourly rate of the equivalent instanceProvider's current pricing page

Serverless cost per month is the invocation charge plus the duration charge:

text
Cost_serverless = (R * Pi) + (R * D * M * Pd)

Always-on cost per month is the hourly rate times the hours in a month. Call it 730 hours as a working average:

text
Cost_alwayson = H * 730

The break-even is where those are equal. Solve for R:

text
R_breakeven = (H * 730) / (Pi + (D * M * Pd))

That is the whole calculation. Below R_breakeven requests per month, serverless is cheaper. Above it, the reserved machine is cheaper. Plug in your provider's current rates, your own measured D, and your chosen M.

Two things fall out of the formula that are worth noticing.

D and M matter more than most people expect. They multiply together in the denominator. A function that takes 800ms at 1GB costs eight times a function that takes 100ms at 1GB, for the same number of requests. Halving your function's runtime moves the break-even point roughly twice as far out. Optimising the code changes the economics, not just the latency.

The invocation fee dominates for very short functions. If D * M * Pd is tiny compared to Pi, you are essentially paying per request regardless of what the request does. For sub-50ms functions this is often the case, and it means micro-optimising further buys you nothing.

4. A Worked Example

These numbers are invented for illustration. They are not any provider's real rates. Do not use them for a decision. Look up your own.

Hypothetical rates. Say invocations cost Pi = 0.0000002 per call, duration costs Pd = 0.000017 per GB-second, and a small always-on instance costs H = 0.02 per hour. Suppose your function takes D = 0.2 seconds at M = 0.5 GB.

Cost of one request under serverless:

text
per_request = 0.0000002 + (0.2 * 0.5 * 0.000017)
            = 0.0000002 + 0.0000017
            = 0.0000019

Cost of the always-on box for a month:

text
0.02 * 730 = 14.60

Break-even:

text
R_breakeven = 14.60 / 0.0000019 ≈ 7,700,000 requests per month

Roughly 7.7 million requests a month, or about 3 requests per second sustained. Under that, the hypothetical serverless option is cheaper. Over it, the box is.

The number itself is meaningless because the inputs are invented. The shape of the result is the point: the break-even landed at a traffic level where the instance would be genuinely busy. The crossing point tends to sit near the utilisation level at which the reserved machine stops being mostly idle.

5. The Costs Both Sides Forget

The formula above is the honest starting point, and it is incomplete. Both models carry costs that never appear in the invocation-versus-hourly comparison.

On the serverless side:

  • Cold starts. When a function has not run recently, the provider must initialise a fresh execution environment before your code runs. The first request pays that penalty, sometimes hundreds of milliseconds, sometimes worse on heavier runtimes. This is not a line item on your bill. It is a cost paid by your users, and on a latency sensitive endpoint it can disqualify serverless entirely.
  • Keeping instances warm. The standard fix is to pay the provider to keep environments initialised and ready. This works, and it converts part of your pay-per-use bill back into a fixed hourly charge. Every warm instance you reserve erodes the advantage you bought serverless for. Provision enough warmth to eliminate cold starts under normal traffic and you have quietly re-invented an always-on server with worse ergonomics.
  • Database connections. This is the one that causes real outages. Each concurrent function execution is its own process wanting its own database connection. A spike that fans out to 500 concurrent executions asks for 500 connections. Your database has a hard connection limit, often well below that, and it will refuse the rest. The fix is a connection pooler, a service that sits between your functions and the database and multiplexes many client connections onto a few real ones. Treat it as mandatory, and remember it is another component to run and pay for.

On the always-on side:

  • Idle capacity. Every hour below full utilisation is money spent on nothing. This is the cost the serverless argument is built on, and it is real.
  • Operational time. Someone patches the OS, rotates certificates, watches memory leaks, handles the instance that stops responding at an inconvenient hour. That work is invisible in the hourly rate and expensive in practice.
  • Autoscaling lag. Adding instances is not instant. Provisioning, boot, health checks, and warmup take time, often minutes. A spike that arrives faster than your scaling policy reacts is a spike your users experience as errors. To avoid this you over-provision headroom, which means paying for capacity you hope not to use.

On both sides:

  • Egress. Data leaving the provider's network is billed by the gigabyte, and the rate is generally the same whichever compute model you chose. For bandwidth heavy workloads this can exceed the compute cost outright, at which point the entire discussion in this post is a rounding error.

6. The Hybrid Pattern Is Usually the Answer

Framing this as a binary choice is the actual mistake. Most systems do not have one traffic shape. They have several, and different parts want different answers.

The pattern I would default to:

  • An always-on core for the steady, latency sensitive traffic. Your main API, your web application, the endpoints a user waits on. This traffic is predictable, keeps the machine busy, and cannot afford cold starts.
  • Serverless for everything spiky and asynchronous. Scheduled jobs, image and video processing, webhook receivers, report generation, queue consumers, occasional bursty endpoints. Work that arrives unpredictably, tolerates a few hundred milliseconds of startup, and would otherwise force you to size your core instance for a peak it sees twice a day.

This is not a compromise. It is applying each pricing model to the traffic shape it is good at. Sizing one always-on fleet to absorb both your steady load and your rare bursts means paying for burst capacity around the clock. Moving the bursts to serverless lets you size the core for the steady state, which is the thing you can predict.

7. Engineer Time Is on the Bill

One number is missing from every calculation above, and at small scale it dominates all of them.

An engineer's hour costs more than a small instance's month. If choosing the theoretically cheaper option costs a week of migration and debugging, you have spent more on the decision than it saves in a year. The saving has to clear that bar before it is a saving at all.

This cuts both ways. Serverless removes patching and capacity planning, which is real time returned. It also introduces cold start debugging, connection pooling, local development friction, and a harder time reproducing production behaviour. Always-on gives you a boring machine that behaves the way your laptop does, and asks for maintenance in return.

Count the hours. They are the largest line item on most small systems, and the one nobody puts in the spreadsheet.

Conclusion

At low traffic, this entire analysis is theatre. Both options cost less than lunch. The difference between them is noise against your salary bill, and the only variable that matters is how fast you can ship. Pick whichever gets the thing in front of users soonest, and spend the saved deliberation on the product.

The calculation starts to matter at scale, and it announces itself. When compute is a visible fraction of your infrastructure bill, when a spike costs real money, when someone asks why the invoice moved: that is the point to sit down with the formula, look up your provider's current rates, measure your actual D, and find out where your break-even sits.

Then check which side of it you are on, and act on the answer rather than the principle.


Run the numbers before the argument. The numbers are usually shorter.

Subscribe to my newsletter

Coming soon.

||