SevyDevy

Guide · Backend

Serverless Trade-Offs: Cold Starts, Limits and Cost Curves

19 min readUpdated By Saket Bhatnagar

Researched and drafted with AI, reviewed and edited by Saket Bhatnagar.

In short

  • Going serverless means your code runs only when an event arrives, such as a web request or a queue message. You pay per run instead of paying for idle servers.
  • The first trade-off is the cold start: the extra wait when a request finds no ready copy of your code, so the platform must set one up first.
  • The second is limits. On AWS Lambda, as of 19 October 2026, one run is stopped after at most 15 minutes, and a copy keeps no memory you can rely on between runs.
  • The third is the cost curve. You pay for every request and every second of compute, so spiky or low traffic is cheap, but steady high volume costs more than always-on servers.
  • Beginners can stop after the section on when not to use serverless. Engineers then get a query that counts cold starts and a queue design that stops database connection storms. They also get cost maths at published prices, where keeping copies warm costs more than twice the whole on-demand bill.

What goes wrong when spiky work runs on always-on servers?

You pay for servers all month, and they still choke on the few days that matter. Serverless functions fit this shape: capacity appears when work arrives and costs nothing while idle.

Picture a common setup. A small invoice service in India turns each sale a shop uploads into a GST invoice PDF and emails it to the buyer. GST is India's goods and services tax. The setup is made up, but the problem is real.

The service has about 1,800 sellers and sends about 2.5 lakh (250,000) invoices a month. It runs on two always-on servers that cost Rs 6,000 a month together.

For most of the month the servers sit nearly idle. In the last three days, sellers rush to send invoices before filing their GST returns, and the queue backs up for hours.

So the team moves the invoice code to serverless functions on AWS Lambda, and the monthly compute bill drops below Rs 1,000. Then three surprises arrive. The first invoice each morning is slow, a bulk job dies halfway, and the database refuses connections on the 30th.

This guide walks through each surprise and what it teaches about serverless trade-offs.

What is serverless computing?

Serverless computing is a way to run code where the cloud provider starts, scales and stops the machines for you. You pay for the requests and the time your code runs. There are still servers; you just never manage them.

Function. In serverless, a function is a small piece of code with one entry point, called the handler. Example: the invoice handler takes one sale and returns one invoice PDF.

Event. An event is whatever wakes the function up: an HTTP request (a call from a browser or app), a new file in storage, a queue message, or a timer. Example: a seller clicking Send creates an HTTP request event.

Execution environment. This is the small, isolated box where one copy of your function runs, with its own memory and temporary disk. The platform creates these boxes, reuses them, and removes them when it decides to.

Concurrency. Concurrency is the number of requests your function is handling at the same moment. On default AWS Lambda, one environment runs one request at a time. So 400 requests at once need 400 environments.

AWS Lambda is the best-known function platform, so this guide uses its documented numbers. Other platforms work in a similar way with different limits. Here is the invoice service after the move.

The invoice service on serverless

Notice that only the function is serverless compute. Storage, email and the database keep running on their own, and the function must reach them on every run.

Diagram connections:

  • Seller's app to HTTPS endpoint
  • HTTPS endpoint to Invoice function (One event per sale)
  • Invoice function to Seller database (Reads seller details)
  • Invoice function to PDF storage (Saves the PDF)
  • Invoice function to Email service (Queues the email)
  • Invoice function to Logs and metrics
  • Seller's app: Uploads a sale and clicks Send
  • HTTPS endpoint: Turns each request into an event
  • Invoice function: Builds the PDF, about 2 seconds a run
  • Seller database: GST number, address, invoice numbers
  • PDF storage: Keeps every invoice PDF
  • Email service: Sends the PDF to the buyer
  • Logs and metrics: Run times, errors, cold starts

Notice what disappeared: there is no box for servers the team patches and resizes. That is the promise of serverless. The rest of this guide is about the price.

What are the main serverless trade-offs?

The main serverless trade-offs are slower first requests (cold starts), hard limits on how long and how big each run can be, and a bill that grows with every request. In return, idle time costs nothing and scaling is automatic.

These costs are not new. A 2019 Berkeley paper predicted that serverless would grow to dominate cloud computing. It also listed open problems, including slow instance startup and weak support for shared state.

Here is how the two setups compare for the invoice service. Timings and the server cost are made up. The serverless bill uses published Lambda prices, worked out later in this guide.

Always-on servers versus serverless functions for the invoice service (timings and server cost made up; Lambda prices as of 19 October 2026, at an assumed Rs 95 per dollar)
Two always-on serversServerless functions
Monthly cost at 2.5 lakh invoicesRs 6,000, busy or idleAbout Rs 800 for requests and compute
Month-end rushQueue backs up for hoursScales out to hundreds of copies
First request after a quiet spellAbout 2 seconds, always warmAbout 4 seconds on a cold start
Longest single runAs long as you like15 minutes, then it is stopped
Memory between requestsKept until a restartMay vanish at any time
Database connectionsA fixed pool of 20One or more per copy, can explode
Who patches the machinesThe teamThe cloud provider
Cost at 40 lakh (4 million) invoicesStill Rs 6,000 if they keep upAbout Rs 12,700 for requests and compute

Every row is a trade, not a verdict. The next sections take the three big ones in turn: cold starts, limits and cost.

What is a cold start in serverless?

A cold start is the extra delay when a request arrives and no ready execution environment exists, so the platform must create one before your code can answer. A warm start reuses a ready environment and skips that delay.

Think of two kinds of geyser at home. An instant geyser heats water only while the tap is open. You pay for power only while you use it, but the first mug of water comes out cold.

A storage geyser keeps a tank hot all day. Hot water comes out at once, but you pay to keep it hot even when nobody bathes. Serverless is the instant geyser. The old servers were the storage geyser.

Where the picture breaks: a geyser serves one tap. In a rush, the platform starts many new environments side by side, and every new one starts cold.

During a cold start, the platform downloads your code, starts a fresh environment with the language runtime, and runs your init code. Init code is everything outside the handler, such as imports and client setup. Only then does the handler run.

What happens when a request arrives

Only the No branch pays the cold start. After a run the environment is frozen and kept for a while, but never forever.

Diagram connections:

  • Invoice request arrives to Ready environment free?
  • Ready environment free? to Run the handler (Yes: warm start)
  • Ready environment free? to Create new environment (No: cold start)
  • Create new environment to Run init code
  • Run init code to Run the handler
  • Run the handler to Freeze and keep for reuse
  • Invoice request arrives: Seller clicks Send
  • Ready environment free?: One left over from an earlier run
  • Create new environment: Download code, start the runtime
  • Run init code: Imports, PDF fonts, clients; billed
  • Run the handler: Build and save one invoice
  • Freeze and keep for reuse: Removed after idle time or within hours

As of 19 October 2026, AWS documents that cold starts typically happen in under 1% of invocations. It says one can last from under 100 milliseconds to over a second.

How long an idle environment is kept is undocumented as of 19 October 2026. The docs say only that Lambda keeps it for some time, and replaces environments every few hours even on busy functions. So after a quiet night, expect the first requests of the morning to start cold.

The invoice service's four-second cold start (made up) came mostly from its own init code. It loaded a large PDF library and three font files. Init is the part of a cold start you control.

Where your code runs matters

Here is a cut-down handler in Python. boto3 is the AWS SDK for Python, and the modules invoice_pdf and invoice_jobs stand in for the team's own code.

python
import json
import boto3
from invoice_pdf import render_invoice    # big PDF and font library
from invoice_jobs import queue_invoice_email

s3 = boto3.client("s3")                    # set up once per environment
BUCKET = "example-invoices"

def handler(event, context):
    sale = json.loads(event["body"])
    pdf = render_invoice(sale)             # runs on every request
    key = f"{sale['seller_id']}/{sale['invoice_no']}.pdf"
    s3.put_object(Bucket=BUCKET, Key=key, Body=pdf)
    queue_invoice_email(sale["buyer_email"], key)
    return {"statusCode": 202, "body": json.dumps({"pdf": key})}

Lines outside the handler run once per environment, during the cold start. Warm requests reuse the PDF library and the storage client for free. Lines inside the handler run on every request.

What just happened? We ran this sample on Python 3.13 with boto3 1.43.115, using a fake S3 client in place of the real one. Three requests returned status 202, and the PDF module loaded once, not three times.

Notice too that the email is only queued, not sent. Waiting on a slow mail server inside the handler would add to every request's time, and to the bill.

What limits does serverless put on your code?

Serverless platforms cap how long one run lasts, how much memory and data it can use, and how many copies run at once. Your design has to fit inside these caps.

These are AWS Lambda's documented numbers for default, on-demand functions as of 19 October 2026. They change over time, so check the quotas page before you design around them.

  • Run time: at most 15 minutes (900 seconds) per invocation. The platform then stops the run, finished or not.
  • Memory: 128 MB to 10,240 MB. CPU grows in proportion to memory, and at 1,769 MB a function gets the equivalent of one virtual CPU.
  • Payload: 6 MB each for the request and the response when the caller waits, and 1 MB for an asynchronous (fire-and-forget) event.
  • Concurrency: 1,000 copies at once per account in each Region (one AWS data-centre area, such as Mumbai) by default, shared by all your functions. New accounts start lower; the quota can be raised.
  • Scaling speed: each function can add up to 1,000 new environments every 10 seconds.
  • Init: 10 seconds. If init runs over, Lambda retries it when the first request arrives, under the function's own timeout.
  • Package: 50 MB zipped when uploaded directly, 250 MB unzipped including layers, or 10 GB as a container image.

The 15-minute wall

The biggest seller, a wholesale cloth trader, sends 50,000 invoices in one click at month-end. The first version looped over all of them in one run. At 2 seconds each that needs about 28 hours, so the run was stopped at 15 minutes.

The fix is to stop thinking of one long job. A small splitter function puts 50,000 messages on a queue, which is a list of waiting tasks that workers take from. Many short runs then build one invoice each.

For long work with many steps, AWS also offers durable functions. They save progress after each step, and as of 19 October 2026 a workflow can run for up to one year.

No memory between runs

A function must be stateless. It cannot count on anything kept in memory or on its temporary disk surviving to the next request. The platform may reuse a warm environment, or remove it without warning.

The team once kept the next invoice number in a global variable. Every environment loads its own copy of that variable, so two copies handed out the same numbers. That is a real problem for GST invoices.

We checked the pattern with two Python processes standing in for two environments. Both handed out invoice numbers 1001 and 1002. Now the database hands out invoice numbers, one at a time.

When should you not use serverless?

Avoid serverless functions when work runs long, needs steady low latency on every request, runs at high flat volume, or must hold connections open. Servers or containers usually fit those jobs better.

Go back to the geysers. If the family bathes one by one from dawn to midnight, a tank kept hot makes sense. If they bathe twice a day, heating on demand wins. Your traffic shape decides, not fashion.

These signs point away from serverless functions:

  • Jobs that run longer than the time cap and cannot be cut into small pieces, like a two-hour video encode.
  • Traffic that is high and flat around the clock, which puts you past the cost break-even.
  • Strict latency targets on every request, where even rare cold starts break a promise to users.
  • Long-lived connections, such as a chat server holding thousands of open network connections.
  • A database that cannot take hundreds of short-lived connections and has no pooler in front.

These signs point toward serverless functions:

  • Spiky or unpredictable traffic, like the month-end invoice rush.
  • Event-driven work: a file lands, a message arrives, a timer fires.
  • Short jobs, from milliseconds to a few minutes each.
  • A small team that would rather build features than run servers.

Many systems mix both. The team plans to keep the spiky invoice and email work on functions. If one large marketplace starts sending 40 lakh steady invoices a month, that customer's traffic moves to a small fixed fleet of containers.

How do you reduce serverless cold starts?

You reduce cold starts by making init smaller, and by paying to keep some environments ready before requests arrive. Measure first, then try the free fixes, then pay only where users wait.

How to count your cold starts

On a cold start, Lambda adds an Init Duration field to the REPORT line it logs after each request. This query for CloudWatch Logs Insights, AWS's log search tool, comes from an AWS Compute Blog post. It turns those lines into a cold-start percentage.

text
filter @type = "REPORT"
| stats sum(strcontains(@message, "Init Duration")) / count(*) * 100 as coldStartPct, avg(@duration)
  by bin(5m)

Run it on the function's log group, the folder that holds its logs. Expect one row per 5-minute window with requests in it. coldStartPct is a percentage, so 25 means one request in four was cold. It counts on-demand cold starts only, because provisioned and SnapStart environments report init in a separate INIT_REPORT line.

Free fixes first

  • Import only what you use. The team split its code so the email-only function never loads the PDF library.
  • Load rarely used parts lazily, inside the branch that needs them, instead of at the top of the file.
  • Keep the package small. Fewer and smaller dependencies download and load faster.
  • Try more memory. CPU grows with memory, so CPU-heavy init can finish sooner, but each second also costs more. Measure both.
  • Use SnapStart where it fits. For Java 11+, Python 3.12+ and .NET 8+, it starts new environments from a snapshot taken after init.

SnapStart has catches, as of 19 October 2026. Outside Java it adds caching and restore charges, it cannot be combined with provisioned concurrency, and anything unique made during init is copied into every environment.

Paying for warm environments

Provisioned concurrency is the AWS name for asking the platform to keep a set number of environments initialised and ready. It is the storage geyser bolted onto your instant one: hot water at once, but you pay to keep it hot.

AWS bills provisioned environments for as long as they are configured, used or not, and it bills their init too. Requests beyond that number still run as normal on-demand copies, with possible cold starts.

The team's plan is to keep 2 ready environments from 9 am to 9 pm, and 20 in those hours on the last three days. Application Auto Scaling, AWS's scaling service, can run this schedule.

At the published US East price of $0.0000041667 per GB-second, that schedule at 1 GB costs about $20.52 in a 30-day month. At an assumed Rs 95 per dollar, that is about Rs 1,949, more than twice the Rs 796 on-demand bill. Requests served by those environments pay a lower duration price, $0.0000097222 per GB-second, which wins a little back.

How do you stop serverless functions from flooding your database?

Put a queue and a concurrency cap between the burst and the database, and share connections through a pooler. Otherwise every new copy opens its own connections, and a rush opens hundreds.

On the 30th, 400 copies of the invoice function each opened a database connection. The team's PostgreSQL server allows 100, the usual default for its max_connections setting. Invoices began failing with connection errors.

Servers share a small, fixed pool of connections inside one process. Serverless copies cannot share a pool, because each lives in its own environment. Three fixes work together: queue the work, cap the copies, and pool the connections.

  • Queue: the splitter writes one message per invoice, so a burst waits in the queue instead of hitting the database.
  • Cap: when an Amazon SQS queue (AWS's managed queue service) triggers the function, Lambda's maximum concurrency setting limits how many copies that queue can start. The console allows 2 to 1,000.
  • Cap the whole function: reserved concurrency sets both a ceiling and a guaranteed share for one function, at no extra charge.
  • Pool: a connection pooler such as Amazon RDS Proxy keeps a few database connections open and shares them, queuing clients it cannot serve at once.

In the diagram, follow one bulk request from the seller to the database. Notice where the cap of 50 sits: between the queue and the workers, so the database never sees more than 50 copies at once.

The month-end bulk job

Short runs of one invoice each never hit the 15-minute wall. The cap of 50 protects the database, and failed messages move aside instead of retrying forever.

Diagram connections:

  • Seller clicks Send all to Splitter function
  • Splitter function to Invoice queue (50,000 messages)
  • Invoice queue to Invoice workers (One invoice per run)
  • Invoice workers to Connection pooler
  • Connection pooler to Seller database
  • Invoice queue to Failed invoices queue (After 3 failed receives)
  • Seller clicks Send all: 50,000 invoices for the month
  • Splitter function: Writes one message per invoice
  • Invoice queue: Holds work until a worker is free
  • Invoice workers: Maximum concurrency 50
  • Connection pooler: Shares a few database connections
  • Seller database: PostgreSQL, max_connections 100
  • Failed invoices queue: Checked by the team each morning

The cap costs time, not invoices. With 50 copies at 2 seconds each, 50,000 invoices drain in about 33 minutes.

The failed invoices queue is a dead-letter queue: a place where messages go after too many failed tries. Here the queue's maxReceiveCount is 3, so a message moves there after its third failed receive.

How much does serverless cost compared with a server?

Serverless cost grows in a straight line with usage, while an always-on server costs the same busy or idle. So serverless is cheaper at low or spiky volume, and servers win past a break-even point.

Lambda charges a small fee per request and a fee for compute time. Compute is measured in GB-seconds: the memory you chose, in gigabytes, times the seconds your code ran, including init.

The invoice function uses 1 GB for about 2 seconds, so each invoice costs 2 GB-seconds. Pause and predict: at what monthly volume does serverless stop beating Rs 6,000 of servers?

This script uses AWS's published US East prices as of 19 October 2026; check the rate for your own Region, such as Mumbai. The exchange rate, Rs 95 per dollar, is rounded from about 94.9, worked out from European Central Bank reference rates that day. The server cost is made up.

python
# Published AWS Lambda prices, US East (N. Virginia), x86, as of 19 Oct 2026
USD_PER_GB_SECOND = 0.0000166667
USD_PER_MILLION_REQUESTS = 0.20
RS_PER_USD = 95             # near the 19 Oct 2026 rate; use today's rate
SERVERS_RS_MONTH = 6000     # two always-on servers (made up)

def serverless_rs(invoices, memory_gb=1.0, seconds=2.0):
    compute = invoices * memory_gb * seconds * USD_PER_GB_SECOND
    requests = invoices / 1_000_000 * USD_PER_MILLION_REQUESTS
    return (compute + requests) * RS_PER_USD

for invoices in (250_000, 1_000_000, 2_000_000, 4_000_000):
    cost = serverless_rs(invoices)
    winner = "serverless" if cost < SERVERS_RS_MONTH else "always-on servers"
    print(f"{invoices:>9,} invoices: Rs {cost:>6,.0f}  cheaper: {winner}")

Run it with Python 3 and you should see exactly this:

text
250,000 invoices: Rs    796  cheaper: serverless
1,000,000 invoices: Rs  3,186  cheaper: serverless
2,000,000 invoices: Rs  6,371  cheaper: always-on servers
4,000,000 invoices: Rs 12,743  cheaper: always-on servers

The compute term drives the bill: invoices times memory times seconds times price. Double the memory or the run time and the compute bill doubles. At 2.5 lakh invoices, requests add only about Rs 5.

Before the free tier, the break-even here is about 18.8 lakh invoices a month; the free tier pushes it a little higher. Below it, the team saves by not paying for idle time. Above it, they pay a premium for not managing servers. That premium may be worth it, but it should be a choice.

Costs the simple maths misses

  • The free tier: 1 million requests and 400,000 GB-seconds a month, as of 19 October 2026. Here it covers 80% of the compute, leaving about Rs 158.
  • The HTTPS endpoint, queue, logs and data transfer usually bill separately, and logs alone can surprise you.
  • Provisioned concurrency bills all the time it is on, about Rs 1,949 a month for the team's schedule, and it switches off the free tier for that function.
  • Retries of failed runs are billed like any other run.
  • On the other side, servers need someone to patch, monitor and resize them. That time is a cost too.

The servers' Rs 6,000 hides an assumption too. They are sized for the month-end peak. If traffic were flat all month, smaller servers might do, and the break-even would come much sooner.

How do you explain serverless trade-offs in a system design interview?

Explain serverless as a choice you make from the traffic shape, then name its costs and show how your design handles each one.

  1. Describe the traffic

    Say how many requests arrive, how spiky they are, and how long each job runs. Here: 2.5 lakh invoices a month, mostly in three days, 2 seconds each.

  2. Make the choice

    Pick serverless for spiky, short, event-driven work. Say plainly that you are trading idle cost for cold starts, limits and per-request pricing.

  3. Handle cold starts

    Measure the cold-start rate first. Keep init small, and pay for ready environments only on user-facing paths at busy hours.

  4. Respect the limits

    Split long jobs into short runs through a queue. Cap concurrency to protect the database, and keep state in a store, never in memory.

  5. Make runs safe to repeat

    Queues can deliver a message twice. Use an idempotency check keyed on the invoice number, so a repeat does nothing.

  6. Do the cost maths

    Estimate GB-seconds per month, find the break-even with servers, and say what traffic would make you switch.

Questions people ask

Does serverless mean there are no servers?
No. Your code still runs on servers, but the cloud provider owns, patches and scales them. You never pick a machine size or log in to one. You upload a function, connect it to events, and pay for the requests and the compute time each run uses.
How long does a serverless cold start take?
It depends mostly on your code. As of 19 October 2026, AWS documents Lambda cold starts from under 100 milliseconds to over a second, typically in under 1% of invocations. Large packages, heavy imports and slow setup code make them longer. Count yours with the Init Duration field in the REPORT log lines.
Can I keep serverless functions warm by calling them every few minutes?
Only partly. On default Lambda, one environment serves one request at a time, so a single ping keeps at most one environment busy and recent. It does nothing for the second or hundredth parallel request in a rush, and Lambda replaces environments every few hours anyway. Provisioned concurrency is the supported way to keep several ready.
Is serverless cheaper than a server?
Only below a break-even volume. Serverless bills per request and per GB-second, so its cost rises in a straight line with traffic. An always-on server costs the same busy or idle. In this guide's example the line crosses at about 18.8 lakh invoices a month, before the free tier. That uses published Lambda prices as of 19 October 2026 and an assumed Rs 95 per dollar.
What is the maximum run time of a serverless function?
On default AWS Lambda, one invocation can run for at most 15 minutes, as of 19 October 2026. Other platforms set their own caps. For longer work, split it into many short runs through a queue, use Lambda durable functions for multi-step workflows, or move the job to containers.
Can a serverless function connect to a normal SQL database?
Yes, but watch the connection count. Each running copy opens its own connections, so a burst of hundreds of copies can pass a limit such as PostgreSQL's usual default of 100. Cap the function's concurrency, open the connection outside the handler so warm runs reuse it, and put a pooler such as RDS Proxy in front.
Is serverless good for a startup?
Often, yes, at the start. A small team pays almost nothing while traffic is low, and the free tier may cover it entirely. Keep business logic separate from the platform's handler, and redo the cost maths as traffic grows and becomes steady, because the break-even moves with your traffic shape.

Sources and further reading

Practise this with Lala

Practise