The Java Problem
Java is the dominant language in enterprise backends, but it has a painful characteristic: the JVM (Java Virtual Machine) does enormous amounts of work at startup. It loads classes, performs Just-In-Time (JIT) compilation, and — if you're using a framework like Spring Boot — runs dependency injection, component scanning, and bean initialization. This can take 6–15 seconds for a typical enterprise Spring Boot application. That's an unacceptable cold start for a user-facing API.
How SnapStart Works
SnapStart solves this by separating the Init Phase from the invocation entirely. Here's the sequence:
-
At deployment time (not request time): When you publish a new Lambda function version, AWS boots the execution environment, runs the entire Init Phase (JVM startup, Spring Boot initialization, your global code), and then takes a memory snapshot of the fully-initialized MicroVM. This snapshot is stored encrypted in S3.
-
At request time: When a cold start would normally occur, AWS doesn't boot a new VM from scratch. Instead, it restores the memory snapshot — essentially resuming the VM from a saved state. The JVM is already initialized, Spring Boot is already running, your global code has already executed.
The result: cold starts drop from 6–15 seconds to under 200 milliseconds for Java functions, because the expensive Init Phase has been pre-computed and cached.
SnapStart Caveats
SnapStart is not magic — it introduces constraints you must design around:
- Uniqueness problem: If your Init Phase generates a UUID, opens a random port, or seeds a random number generator, all restored snapshots will have the same UUID/seed. AWS provides lifecycle hooks (
beforeCheckpointandafterRestore) via theCRaC(Coordinated Restore at Checkpoint) interface so you can re-initialize anything that must be unique per instance. - Network connections: Any TCP connections opened during Init Phase will be stale after snapshot restoration. Close connections in
beforeCheckpointand reopen them inafterRestore. - Supported runtimes: SnapStart is currently available for Java 11+, Python 3.12+, and .NET 8+. It is not available for custom runtimes or container images.
- Version requirement: SnapStart only works on published Lambda versions, not on
$LATEST.
// Implementing CRaC hooks for SnapStart correctness
import org.crac.Context;
import org.crac.Core;
import org.crac.Resource;
public class MyHandler implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent>, Resource {
private DatabaseConnection dbConn;
public MyHandler() {
// Runs during Init Phase (before snapshot)
this.dbConn = DatabaseConnection.connect();
Core.getGlobalContext().register(this); // Register for CRaC hooks
}
@Override
public void beforeCheckpoint(Context<? extends Resource> context) {
// Called before AWS takes the memory snapshot
dbConn.close(); // Close stale-able resources
}
@Override
public void afterRestore(Context<? extends Resource> context) {
// Called after snapshot is restored, before handler runs
dbConn = DatabaseConnection.connect(); // Reopen fresh connection
}
@Override
public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent event, Context context) {
return dbConn.query(event);
}
}