AWS Lambda SnapStart: Eliminating Java Cold Starts

Java on AWS Lambda has always had an Achilles heel: cold starts. A typical Spring Boot application can take 5-10 seconds to cold start on Lambda—unacceptable for synchronous APIs. AWS Lambda SnapStart, announced at re:Invent 2022 and now generally available, fundamentally solves this problem by taking a snapshot of the initialized JVM and restoring it on cold start. In this comprehensive guide, I will explain how SnapStart works, benchmark its performance, and discuss critical implementation considerations around uniqueness and security.

The Cold Start Problem

Lambda cold starts occur when AWS provisions a new execution environment. For Java, this includes:

  • Downloading and extracting your deployment package
  • Starting the JVM
  • Loading classes (class loading is lazy but significant)
  • Running static initializers
  • Initializing your dependency injection container (Spring, Micronaut)

Benchmarks from our production Spring Boot API (without SnapStart):

MemoryCold Start (p99)Warm (p99)
512 MB11,200 ms45 ms
1024 MB6,800 ms28 ms
2048 MB4,200 ms18 ms

How SnapStart Works

flowchart TB
    subgraph Publish ["Version Publication"]
        Init["Initialize Function"] --> Snapshot["Capture Memory Snapshot"]
        Snapshot --> Encrypt["Encrypt & Store"]
    end
    
    subgraph ColdStart ["Cold Start with SnapStart"]
        Restore["Restore Snapshot"] --> Decrypt["Decrypt Memory"]
        Decrypt --> Resume["Resume Execution"]
    end
    
    subgraph Traditional ["Traditional Cold Start"]
        Download["Download Package"] --> JVM["Start JVM"]
        JVM --> Load["Load Classes"]
        Load --> DI["Init Spring/DI"]
    end
    
    style Restore fill:#C8E6C9,stroke:#2E7D32
    style Download fill:#FFCDD2,stroke:#C62828

When you publish a Lambda version with SnapStart enabled, AWS:

  • Invokes your function’s initialization code
  • Takes a snapshot of the entire JVM memory state (using Firecracker’s snapshot capability)
  • Encrypts and stores the snapshot

On cold start, Lambda restores from the snapshot instead of re-initializing. The result is sub-200ms cold starts for most Java applications.

Enabling SnapStart

# SAM template
MyFunction:
  Type: AWS::Serverless::Function
  Properties:
    Runtime: java11 # or java17
    SnapStart:
      ApplyOn: PublishedVersions
    AutoPublishAlias: live

Or via CLI:

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

aws lambda publish-version --function-name my-function

The Uniqueness Problem

SnapStart introduces a critical architectural challenge: values computed during initialization are frozen in the snapshot. This includes:

  • Random numbers: SecureRandom seeds
  • Timestamps: Cached Instant.now()
  • UUIDs: Pre-generated identifiers
  • Connection IDs: Database or network connections

If your application generates a UUID during static initialization and caches it, every cold-started instance will have the SAME UUID—a catastrophic bug for distributed systems.

Solution: Runtime Hooks

AWS provides lifecycle hooks to regenerate state after snapshot restore:

import software.amazon.lambda.crac.Core;
import software.amazon.lambda.crac.Resource;

public class UniqueIdGenerator implements Resource {
    
    private String instanceId;
    
    public UniqueIdGenerator() {
        Core.getGlobalContext().register(this);
        regenerateId();
    }
    
    @Override
    public void beforeCheckpoint(Context<? extends Resource> context) {
        // Called before snapshot - clear sensitive state
        this.instanceId = null;
    }
    
    @Override
    public void afterRestore(Context<? extends Resource> context) {
        // Called after restore - regenerate unique values
        regenerateId();
    }
    
    private void regenerateId() {
        this.instanceId = UUID.randomUUID().toString();
    }
}

Performance Benchmarks

Same Spring Boot API with SnapStart enabled:

MemoryCold Start (Before)Cold Start (After)Improvement
512 MB11,200 ms890 ms92%
1024 MB6,800 ms320 ms95%
2048 MB4,200 ms180 ms96%

Key Takeaways

  • SnapStart reduces Java cold starts by 90-96%
  • Works with Java 11 and Java 17 runtimes
  • Requires published versions (not $LATEST)
  • Implement CRaC hooks for unique value regeneration
  • Review code for initialization-time secrets and random values
  • No additional cost—included in Lambda pricing

Discover more from C4: Container, Code, Cloud & Context

Subscribe to get the latest posts sent to your email.

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.