AWS
6 min readSeptember 21, 2026

AWS Lambda SnapStart: Eliminating Cold Starts Without Provisioned Concurrency

CO
Coding Protocols Team
Platform Engineering
AWS Lambda SnapStart: Eliminating Cold Starts Without Provisioned Concurrency

Quick answer

SnapStart resumes new Lambda execution environments from a cached Firecracker microVM snapshot instead of re-running init from scratch — cutting cold starts from seconds to sub-second for supported runtimes. The catch: anything unique generated during init (random values, keys, connection IDs) is identical across every restore unless you explicitly regenerate it.

6 min read · AWS

Lambda cold starts come from re-running a function's initialization code — loading the runtime, pulling in dependencies, opening database connections, warming caches — on every new execution environment. For runtimes with heavier init phases (Java's JVM startup and class loading being the canonical example), that can add seconds of latency to the first invocation an environment ever handles.

SnapStart takes a different approach than the usual fixes (keeping functions warm, provisioned concurrency): instead of running init faster, it avoids running it again at all.


How It Works

When SnapStart is enabled and you publish a new function version, Lambda invokes your initialization code once, then takes a Firecracker microVM snapshot of the fully-initialized execution environment — memory and disk state included. That snapshot is encrypted and cached.

From then on, when Lambda needs a new execution environment for that version, it resumes from the cached snapshot instead of booting a fresh environment and running init from scratch. The init code doesn't run again; the environment simply picks up exactly where the snapshot was taken, already warm.

This is the same microVM technology (Firecracker) that already isolates Lambda execution environments from each other — SnapStart doesn't introduce a new virtualization layer, it just adds a checkpoint/restore capability on top of it.


Supported Runtimes

SnapStart supports Java (11 and later), Python (3.12 and later), and .NET (8 and later) as managed runtimes. Java was the original runtime SnapStart launched with; Python and .NET support followed later, expanding to additional AWS regions afterward. As of September 2026 (AWS added this in July 2026), SnapStart also supports functions packaged as container images. Using an AWS base image for Java, Python, or .NET gives you the same experience as a ZIP deployment; a custom base image also works but needs extra setup — a com.amazonaws.lambda.feature.snapstart="Allow" label in the Dockerfile plus the hook implementation AWS documents separately for container images. Check current regional availability before assuming it's live everywhere, since new capabilities like this typically roll out to commercial regions in waves rather than everywhere simultaneously.


The Unique-State Gotcha

This is the part that actually breaks production code if you don't design for it.

Because many execution environments resume from the same cached snapshot, anything your init code generated and expected to be unique per environment is instead identical across every environment restored from that snapshot — until each one diverges after resuming. Concretely, at risk:

  • Random numbers or UUIDs generated during init (e.g., a request ID seed, a correlation ID base)
  • Cryptographic keys, IVs, or nonces generated during init
  • Database connection objects and their underlying TCP connections — a connection opened before the snapshot was taken doesn't survive being resumed on a different host in any meaningful sense, and reusing it silently can produce confusing failures rather than a clean reconnect
  • Any value derived from "the current time" at init, if your code treats that value as fixed for the environment's lifetime

AWS's documented mitigation is runtime lifecycle hooks — beforeCheckpoint and afterRestore — that let your code run logic specifically at snapshot time and specifically at resume time. The pattern: don't do anything unique-per-environment in your normal init path if that path runs before the snapshot; instead, do it in an afterRestore hook, which runs fresh on every single resume, guaranteeing it actually executes per-environment rather than once-and-cached.

java
1// Java example using the CRaC-based hook API SnapStart exposes
2import org.crac.Core;
3import org.crac.Resource;
4
5public class ConnectionManager implements Resource {
6    private Connection dbConnection;
7
8    public ConnectionManager() {
9        Core.getGlobalContext().register(this);
10    }
11
12    @Override
13    public void beforeCheckpoint(org.crac.Context<? extends Resource> context) {
14        // Close the connection before the snapshot is taken —
15        // don't freeze a live TCP connection into the snapshot.
16        if (dbConnection != null) {
17            dbConnection.close();
18        }
19    }
20
21    @Override
22    public void afterRestore(org.crac.Context<? extends Resource> context) {
23        // Runs fresh on every single environment restore.
24        // Re-establish the connection and regenerate anything unique here.
25        dbConnection = openFreshConnection();
26    }
27}

If you skip this and your code just opens a connection or generates a key once during normal init, expecting normal per-invocation cold-start semantics, SnapStart will hand you a lot of environments quietly sharing state they shouldn't.


AWS Cost & Architecture Review Checklist

The questions we ask in a paid AWS review — rightsizing, storage classes, network egress, and the usual five-figure surprises. Plain Markdown.

Free. Instant download. You'll also get the occasional deep-dive from the newsletter — unsubscribe anytime.

Pricing

SnapStart pricing is split from ordinary Lambda invocation pricing, and it isn't free for every runtime. Two SnapStart-specific charges apply: a caching charge (billed per GB-second, with a minimum cache duration per published function version) for keeping the snapshot ready to restore from, and a restore charge (billed per GB) each time an environment actually resumes from the snapshot. For Java managed runtimes, both charges are currently waived — Java runs on SnapStart at no additional cost beyond normal invocation billing. For Python and .NET managed runtimes, both the caching and restore charges apply. Verify current rates directly against the AWS Lambda pricing page before budgeting, since per-unit SnapStart pricing is granular enough (fractions of a cent per GB) that it's easy to misquote from memory.

Ordinary Lambda billing — duration, requests, free tier — is unaffected and applies on top as normal.


Frequently Asked Questions

Does SnapStart replace provisioned concurrency?

For many workloads, yes — SnapStart addresses the same cold-start latency problem without the standing cost of keeping environments warm and idle. They're not mutually exclusive, but if SnapStart already gets your cold start into an acceptable range for a supported runtime, provisioned concurrency's ongoing per-hour cost becomes harder to justify for that function.

Does enabling SnapStart require code changes?

Enabling it is a configuration change (on the published function version), not a code change — no code changes are required for a function to start benefiting from a faster cold start. Code changes (the beforeCheckpoint/afterRestore hooks) are only required if your init code produces something that must be unique per execution environment, which is common enough in real applications that you should audit for it before enabling SnapStart in production.

Why does SnapStart only apply to published versions, not $LATEST?

Snapshots are tied to a specific, immutable function version because the snapshot captures the exact state of that version's code and init output — $LATEST can change at any time, which would make a cached snapshot of it stale or incorrect the moment the code changes. Publish a version to get a stable snapshot target.

Can I use SnapStart with VPC-connected functions?

Yes, but be especially careful with the unique-state gotcha here: a VPC-attached ENI and any connections through it are exactly the kind of per-environment state that shouldn't be captured in the snapshot and reused blindly across restores. Follow the same beforeCheckpoint/afterRestore pattern for any VPC-dependent connection setup.


For the broader serverless architecture patterns SnapStart fits into, see AWS Lambda: Serverless Architecture Patterns.

Fighting cold-start latency on a Java or .NET Lambda function? Talk to us at Coding Protocols — we help teams adopt SnapStart correctly, including auditing for the shared-snapshot state issues that don't show up until production traffic hits them.

Official References

Was this article helpful?

Be the first to rate this article

Related Topics

AWS Lambda
SnapStart
Serverless
Cold Start
Java
Python
.NET
Firecracker

Found this useful? Share it.

Practice this

Related tools

Read Next