Lambda cold starts: what actually causes them in 2026 (VPC probably isn't it)
Search "Lambda cold start" and most results say the same thing: VPC-attached functions add 1-10 seconds of cold start latency, so avoid VPC if you can. That was true before 2019. Since AWS launched Hyperplane-based ENIs, VPC networking setup for Lambda typically adds under 50ms — not seconds. If you're still avoiding VPC to fix cold starts, you're optimizing for a cost that mostly disappeared five years ago, and missing what actually drives cold start time today.
What actually happens during a Lambda cold start?
A cold start has two phases: Init and Invoke. Init downloads and unpacks your deployment package, starts the language runtime, and runs any code outside your handler function (SDK client construction, config loading, DB connection setup). Invoke then runs your handler against the incoming event. Only Init is the "cold" part — Invoke duration is the same whether the environment is warm or cold.
| Phase | What happens | Typical duration |
|---|---|---|
| Init — download & unpack | Deployment package (or container image layers) is fetched and extracted | Scales with package size — tens of ms to 1s+ for large packages |
| Init — runtime bootstrap | Language runtime process starts (JVM, CLR, Python interpreter, Node process) | ~10ms (Python/Node) to 200-400ms+ (JVM/CLR) depending on runtime |
| Init — your init code | Everything outside the handler: SDK clients, DB pools, config fetches | Fully within your control — the most common place cold start time hides |
| Invoke | Your handler runs against the event | Same cost whether warm or cold |
How do you read InitDuration in CloudWatch Logs Insights?
Every cold invocation's REPORT log line includes an Init Duration field alongside Duration and Billed Duration. Query it directly to find your actual cold start distribution rather than guessing from user reports.
fields @timestamp, @initDuration, @duration, @billedDuration, @memorySize
| filter ispresent(@initDuration)
| stats count() as coldStarts,
avg(@initDuration) as avgInitMs,
pct(@initDuration, 95) as p95InitMs,
max(@initDuration) as maxInitMs
by bin(1h)`ispresent(@initDuration)` is the filter that isolates cold starts — warm invocations don't emit an Init Duration field at all. If p95 InitMs is climbing over time with no code changes, check deployment package size first; it's the most common silent regression (a new dependency, an unused SDK import, a bundler misconfiguration).
Myth: VPC adds 1-10 seconds to cold starts
Before 2019, attaching a Lambda function to a VPC meant creating a dedicated Elastic Network Interface (ENI) per function per subnet/security-group combination on every cold start — that provisioning step genuinely took 10-30 seconds. AWS's Hyperplane-based networking, rolled out in 2019, pre-creates and shares ENIs across functions using the same subnet and security group. VPC attachment now typically adds well under 50ms to cold start time. If your team's runbook still says "remove VPC to fix cold starts," that guidance is six years out of date.
What actually causes slow cold starts now
- Runtime choice — JVM and .NET CLR startup is inherently slower than Python or Node's interpreter startup. A Java function with a large dependency tree can add 300-600ms of pure runtime bootstrap before your code runs at all.
- Deployment package size — unpacking a 200MB package takes measurably longer than a 20MB one. Unused dependencies, debug symbols, and bundling entire SDKs instead of the specific clients you use are the usual culprits.
- Init-phase code — SDK client construction, DB connection pool setup, and synchronous config or secret fetches all run during Init, on the cold path, for every cold invocation. Move anything that doesn't need to run before the first event out of the top-level init code.
- Memory allocation — Lambda allocates CPU proportionally to configured memory. A function at 256MB gets less CPU during Init than the same function at 1024MB, which can mean a slower cold start even though you're paying to "save" memory.
The two mitigations worth using, and when they pay off
| Mitigation | What it does | Cost | Best for |
|---|---|---|---|
| SnapStart | Initializes once at publish/version time, then restores a snapshot on cold start instead of re-running Init | No extra charge beyond a small per-restore cost; can be combined with Provisioned Concurrency | Java, Python, and .NET functions with expensive Init code (large dependency graphs, JVM startup) |
| Provisioned Concurrency | Keeps N execution environments pre-initialized and warm at all times | $0.0000041667 per GB-second of provisioned capacity — roughly $5.48/month for one 512MB unit kept warm 24/7 | Latency-sensitive, spiky, or user-facing endpoints where even an occasional cold start breaks an SLA |
Provisioned Concurrency's breakeven is a capacity question, not a guess: one 512MB unit costs roughly $5.48/month kept warm continuously (0.5 GB × 2,628,000 seconds/month × $0.0000041667/GB-second). If a function handles bursty traffic where cold starts are rare and tolerable, that's an easy cost to avoid. If it's on the critical path for checkout, login, or an API with a strict p99 SLA, $5-6/month per warm instance is usually far cheaper than the cost of a slow first request during a traffic spike.
Related reading
Frequently asked questions
Frequently asked questions
Does VPC still cause Lambda cold starts in 2026?
No, not meaningfully. Before 2019, VPC-attached Lambda functions created a dedicated ENI per cold start, adding 10-30 seconds. AWS's Hyperplane networking architecture pre-creates and shares ENIs across functions in the same subnet and security group, reducing VPC networking overhead to typically under 50ms. VPC is no longer the primary cold start cost for most functions.
How long can a Lambda cold start take?
For standard on-demand invocations, the Init phase is capped at 10 seconds — if it doesn't complete in time, Lambda retries Init on the next invocation using your configured function timeout. In practice, most cold starts for lightweight runtimes (Python, Node) with reasonable package sizes complete Init in under 500ms. Java and .NET functions with large dependency graphs and no SnapStart can take 1-3 seconds.
What's the difference between SnapStart and Provisioned Concurrency?
SnapStart initializes your function once when you publish a version, takes a snapshot of the initialized execution environment, and restores from that snapshot on cold start instead of re-running Init every time. Provisioned Concurrency keeps a set number of execution environments fully initialized and warm continuously, at an ongoing per-GB-second cost. SnapStart is essentially free beyond a small per-restore charge; Provisioned Concurrency costs roughly $5.48/month per 512MB unit kept warm 24/7, but guarantees zero Init-phase latency, not just a faster one.
Can I use SnapStart and Provisioned Concurrency together?
Yes, as of a change AWS made available around re:Invent 2023 — earlier documentation said the two were mutually exclusive, but they can now be combined on the same function version for runtimes that support SnapStart (Java, Python, .NET).
How do I find how much of my Lambda latency is cold start vs actual execution?
Query CloudWatch Logs Insights with `filter ispresent(@initDuration)` to isolate cold invocations, then compare @initDuration against @duration for the same requests. This separates the one-time Init cost from your handler's actual execution time, which is what you should be optimizing separately — a fast warm function with a slow cold start needs a different fix than a function that's just slow every time.
Related reading
Still debugging incidents manually?
Nuberio does this automatically — root cause in under 60 seconds, delivered to WhatsApp or Slack.