WritingAWS Lambda SnapStart: How It Works, What It Fixes, and When to Use It — Clixo
6 min readaws, lambda, snapstart, serverless, performance

AWS Lambda SnapStart: How It Works, What It Fixes, and When to Use It

A deep dive into AWS Lambda SnapStart — how snapshot-based initialization works, which runtimes it supports, lifecycle hooks, and when it replaces provisioned concurrency.

Java Lambda functions have historically suffered cold starts measured in seconds — not milliseconds. A Spring Boot function initializing its application context can take 8-12 seconds before it handles its first request. This made Java a poor fit for any Lambda use case where latency consistency mattered. AWS SnapStart changes that calculus significantly, and understanding how it works determines whether it belongs in your architecture.

What AWS Lambda SnapStart Actually Does

Standard Lambda cold starts require four sequential steps: allocate a microVM, load the runtime, run initialization code, then handle the invocation. Steps one through three represent irreducible overhead — they happen every time a new execution environment is needed.

SnapStart breaks that sequence by checkpointing the execution environment after step three completes. AWS takes a snapshot of the fully initialized execution environment — memory state, file system, network configuration — and stores it. When a new execution environment is needed, Lambda restores from the snapshot instead of initializing from scratch.

The result: subsequent cold starts skip the initialization phase entirely. A Java function that took 6 seconds to cold-start can drop to under 1 second — sometimes under 300ms — with no application code changes.

Which Runtimes Support SnapStart

SnapStart launched with support for Java on Corretto 11, then expanded to Corretto 17 and Corretto 21. As of mid-2025, it is a Java-only feature. AWS has indicated intent to expand runtime support, but the timing is unconfirmed.

If your Lambda functions run on Node.js, Python, or other runtimes, SnapStart is not currently available. For those runtimes, cold start optimization relies on package size reduction, initialization code structure, and provisioned concurrency.

Enabling SnapStart

Enabling SnapStart is a single configuration change on the Lambda function:

aws lambda update-function-configuration \
  --function-name my-function \
  --snap-start ApplyOn=PublishedVersions

SnapStart only applies to published versions — it does not work on $LATEST. This means your deployment process must publish a version after each code update. If you are using Lambda aliases and weighted traffic routing, you are likely already publishing versions. If not, adding version publication is a small workflow change.

After enabling SnapStart, the first deployment after the setting change will take longer than usual — Lambda is initializing and snapshotting the new version. Subsequent deployments follow the same pattern.

The Catch: Snapshot Restoration and State

SnapStart restores an execution environment from a frozen snapshot. Any state that was valid at snapshot time but is no longer valid at restore time will cause problems.

The most common issues:

Unique identifiers generated at init: If your initialization code generates a UUID, cryptographic seed, or random value meant to be unique per execution environment, all restored environments will share the same value. This breaks uniqueness guarantees.

Network connections: A database connection or HTTP keep-alive established during initialization will be stale or invalid after restore. Attempting to use it will produce errors.

Time-sensitive tokens: Authentication tokens fetched during initialization expire. A token that was valid when the snapshot was taken may be expired when the environment is restored hours or days later.

SnapStart Lifecycle Hooks

AWS provides two lifecycle hooks specifically designed to handle snapshot-state invalidation:

  • beforeCheckpoint: runs before the snapshot is taken. Use it to flush and close any state that should not be persisted.
  • afterRestore: runs after the environment is restored from snapshot but before the handler is invoked. Use it to re-establish connections, regenerate unique identifiers, and refresh tokens.

In Java, implement these via the RuntimeHook interface:

public class MyHook implements RuntimeHook {
    @Override
    public void beforeCheckpoint(Context context) {
        // Close DB connections, flush state
    }
 
    @Override
    public void afterRestore(Context context) {
        // Re-establish DB connections, refresh tokens
    }
}

Teams using frameworks like Quarkus or Micronaut with SnapStart support get these hooks managed automatically for common resources. Spring Boot integration has improved but may require manual hook implementation depending on which beans you initialize.

SnapStart vs Provisioned Concurrency

These two features solve the same problem — cold start latency — with different mechanisms and different cost profiles.

Provisioned Concurrency keeps initialized execution environments warm at all times. You pay for the concurrency even when no invocations are occurring. The cost is continuous.

SnapStart eliminates the initialization cost by restoring from a snapshot. You do not pay for idle warm environments. The cost is only incurred during actual cold starts, which are now measured in milliseconds instead of seconds.

For most Java workloads, SnapStart is the better starting point. Provisioned Concurrency then becomes a tool for the subset of invocations where even a fast cold start is unacceptable — typically user-facing, latency-SLA-bound endpoints.

When to Use SnapStart Over Provisioned Concurrency

  • Traffic pattern is bursty or unpredictable
  • The function is invoked infrequently enough that idle provisioned concurrency cost would be significant
  • Post-SnapStart cold start duration (sub-500ms) is within acceptable p99 latency bounds

When to Layer Both Together

  • User-facing endpoints with strict latency SLAs
  • Functions on the critical authentication or payment path
  • Traffic patterns are predictable enough to size provisioned concurrency accurately

Use SnapStart to drop base cold start cost to near zero, then apply provisioned concurrency only to the functions and traffic windows where cold starts remain unacceptable. Auto-scale provisioned concurrency on a schedule to match traffic patterns.

Practical Limits and Considerations

  • SnapStart snapshots are stored per published version. Old version snapshots are deleted when the version is deleted.
  • SnapStart is not compatible with Lambda functions configured with Elastic Network Interfaces inside a VPC if those ENIs are provisioned during initialization. ENI attachment must move to afterRestore.
  • Functions with very large heap sizes at init time produce larger snapshots, which adds restore time. Lean initialization remains important even with SnapStart.

Summary

SnapStart is the most significant improvement to Java Lambda cold starts since the platform launched. For any team running Java-based Lambda functions — Spring Boot, Quarkus, Micronaut, or plain Java — enabling SnapStart should be an early step in your infrastructure optimization backlog. The configuration cost is low, the lifecycle hook work is manageable, and the cold start improvement is substantial.

If you are building production systems on AWS and want infrastructure decisions made with this level of depth from the start, talk to Clixo. We ship cloud-native systems that perform correctly under real-world conditions.