The idea: no server between calls
A classic web server is started once and keeps running. A serverless function such as AWS Lambda scales to zero: when no request comes, nothing runs and nothing is billed. The price is paid by the first request. Before its handler can run, the platform must build an execution environment for it. That wait is the cold start. Later requests reuse the environment and only run the handler: they are warm.
What a cold start does
Lambda calls the first part the INIT phase and the handler the INVOKE phase. The page uses these numbers (rough, but in the right range):
| step | what happens | Node.js 22 | Java 21 |
|---|---|---|---|
| create sandbox | boot a Firecracker microVM on a worker host | 125 ms | 125 ms |
| download code | fetch and unpack the zip (5 MB / 50 MB) | 50 / 250 ms | 50 / 250 ms |
| start runtime | start the language runtime | 120 ms | 450 ms |
| init code | code outside the handler: imports, SDK clients, DB connection, framework | 180 ms | 700 ms |
| handler | the request itself | 50 ms | 50 ms |
| cold total | with the 5 MB zip | 525 ms | 1375 ms |
The first request in Demo: cold start, then warm takes 525 ms; the second takes 50 ms. Only the handler is your business logic; the rest is set-up.
Warm, frozen, reclaimed
After a response, Lambda freezes the environment: the process stays in memory but gets no CPU. The next request thaws it and runs only the handler. Global variables, open connections and files in /tmp survive, which is why init code is the place for clients and connection pools. A frozen environment is kept only for a while: AWS does not publish the time, and the page assumes about 10 minutes. After 5 idle minutes the call is still warm (Demo: idle 5 min, still warm); after 15 it is cold again (Demo: idle 15 min, cold again).
A burst: one cold start per request
An environment handles one request at a time. If three requests arrive together and only one environment is free, the other two get new environments, each with its own cold start. In Demo: a burst of 3 = 3 cold starts all three wait 525 ms; the next burst finds three warm environments and takes 50 ms each. A traffic spike after a quiet period is therefore the worst case: many users see the cold start at once.
The runtime and SnapStart
A JVM starts slower than Node.js, and Java frameworks do a lot at start-up (class loading, dependency injection). SnapStart runs INIT once when a version is published, takes a snapshot of the microVM's memory, and restores that snapshot on a cold start instead of starting the runtime and running init again. In Demo: Java vs SnapStart the cold start drops from 1375 ms to 425 ms; warm calls are 50 ms either way. Code that must be unique per environment (random seeds, connections) has to be refreshed after a restore.
Provisioned concurrency vs a long-running server
Provisioned concurrency asks Lambda to keep N environments initialized at all times. In Demo: provisioned concurrency two of the three burst requests are warm, the third spills over to an on-demand environment and is cold, and the 15 idle minutes cost 2 × 15 = 30 instance-minutes. A long-running server ran its init once at deploy and never stops, so no request ever waits for it, and one process can serve many requests at once with an event loop (Demo: long-running server). It is paid for every idle minute too.
| Lambda, on demand | provisioned concurrency | long-running server | |
|---|---|---|---|
| first request after idle | cold start | warm (up to N at once) | fast |
| burst above capacity | one cold start per extra request | cold above N | queues in the server, or a new instance must start |
| idle cost | none | N environments | the whole instance |
| requests per instance | one at a time | one at a time | many at once |
Other ways to shrink a cold start: a smaller package (try the 50 MB zip in Options), fewer dependencies, lazy initialization, a lighter runtime, and more memory, which also gives more CPU. See also Kubernetes autoscaling for pods that scale up, vertical vs horizontal scaling, containers vs VMs, JIT tiering for why a fresh JVM is slow, and connection pools.
What the page leaves out
The numbers are fixed examples; real cold starts vary with memory size, region, VPC networking and luck. The page leaves out Lambda extensions and their own init, the 10-second INIT limit, the concurrency limit and throttling (429), container image functions and their lazy-loaded layers, how the placement service picks a worker host, the pre-warming Lambda does on its own, and the cost per GB-second.