The Runtime Theory
SystemDSAarchitecture

Cold Start: Container Init, Code Load, Handler Wiring, First Request

A step-by-step walk from the cold container to the first served request — and the arithmetic of how cold starts cost you latency.

The Runtime Theory Team3 min read06 steps

trace spine

  1. 01 container is scheduled
  2. 02 runtime initializes
  3. 03 code and deps load
  4. 04 handler is wired
  5. 05 first request is served
  6. 06 warm path takes over

The cold start is the moment a fresh container must do everything a running one already did: boot the OS, start the runtime, load the code, and then answer one user's request. The total is the sum of stages, and each stage has a price. Walk a Lambda-style cold start.

trace stepSystem
A request arrives for a function with zero warm instances. The platform picks a host, reserves resources (CPU quota, memory), and pulls the image — cached layers on the host, so the pull is usually the delta: 50–200ms for cached base layers, seconds for uncached. In Lambda's architecture this stage also includes network plumbing and security-group setup, which is part of why cold starts aren't just "docker run."
trace stepSystem
The process starts: the OS loads the binary and its shared libraries, the JVM or Node or Python interpreter spins up. A JVM cold boot is 300–800ms before your code runs a line; Node and Python are 50–150ms; a Go binary ~20ms. This stage is pure overhead — none of it is your code, and most of it is the language's fault. The single biggest lever here is language choice, not tuning.
trace stepSystem
Your handler module is imported: dependency graphs resolve, config is read, DB connection pools initialize, SDK clients construct. This is the stage that surprises people — a Lambda with 30 imports and a DB pool can spend 200–400ms here. The classic cold-start tax is the eager connection pool: every cold start opens database connections the warm path never needs.
trace stepSystem
The platform registers the handler, sets up the invocation plumbing (event loop, error channel, response serializer), and — in Lambda's model — signals readiness. One subtlety: the platform doesn't wait for your first request to finish; it reports "init complete" at the end of this stage, which is why billed init time and your perceived cold start can differ.
trace stepSystem
The request executes: handler logic, downstream calls, response. This first request carries the whole startup cost, so the p95 user experiences init + runtime + load + request. Numbers on Lambda's Node.js path: ~200–800ms cold vs ~5–30ms warm for the same handler — a 20–100x gap that lives entirely in the stages above. The JVM path: 1–3s cold, ~30–60ms warm.
trace stepSystem
The instance survives; the platform reuses it for the next request. Warm requests skip every stage above — they are plain function calls. Keep-alive strategies (Lambda's provisioned concurrency, long-running server processes, idle-timeout tuning) exist to convert cold requests into warm ones, at the price of paying for idle instances.
text
image pull        ~50–200ms   (cached layers)
runtime boot      ~60–150ms   (Node starts, event loop primed)
code load         ~150–400ms  (imports, config, DB pool)
handler wiring    ~20–50ms    (platform plumbing)
first request     ~20–200ms   (your handler, at cold-cache state)
─────────────────────────────
total cold        ~300–1000ms vs warm ~5–30ms

The ledger: every cold start pays image pull + runtime boot + code load + wiring before the user's request even begins, and every one of those stages is fixed overhead per instance — no traffic volume amortizes it. The entire discipline of cold-start engineering — snapshots, provisioned concurrency, lazy init, AOT — is the attempt to move those four stages from "per instance" to "once," so the first request a user sees costs what the millionth costs.