SnapStart
Lambda SnapStart snapshots an initialized execution environment and restores it on later cold starts, reducing startup latency. Because the adapter runs your web application as a separate process, the application does not have direct access to the SnapStart lifecycle. The adapter bridges this gap with two optional HTTP hooks.
Hooks
| Variable | When the adapter calls it | Use it to |
|---|---|---|
AWS_LWA_SNAPSTART_BEFORE_CHECKPOINT_PATH | Before the snapshot is taken | Drain or close resources that will not survive the snapshot |
AWS_LWA_SNAPSTART_AFTER_RESTORE_PATH | After restore, before serving traffic | Reconnect, refresh credentials, reseed randomness, regenerate unique identifiers |
Both hooks are opt-in and independent — each fires only when its variable is set.
How it works
The adapter always registers for the SnapStart lifecycle; the Lambda runtime invokes the hooks only when your function runs under SnapStart. When it does, the adapter participates as follows:
-
Before checkpoint — if
AWS_LWA_SNAPSTART_BEFORE_CHECKPOINT_PATHis set, the adapter sends an emptyPOSTto that path on your application, then signals Lambda that it is ready for the snapshot. Initialization has already waited for your application to report ready by this point, so the snapshot is never taken of a still-booting app. -
After restore — Lambda restores the environment. The adapter first refreshes its own HTTP connection to your application (so it never reuses a connection captured in the snapshot); then, if
AWS_LWA_SNAPSTART_AFTER_RESTORE_PATHis set, sends an emptyPOSTto that path; and finally re-runs the readiness check before admitting traffic.
Note:
AWS_LWA_ASYNC_INITis ignored under SnapStart (and under Provisioned Concurrency). It works around the short initialization limit for on-demand cold starts by reporting init complete before the application is ready; neither of those environments has that limit, and finishing early would snapshot — or serve — a half-initialized application. The adapter logs a warning when it ignores the setting.
Each hook is an empty POST, and your application must respond with a 2xx status. A non-2xx response or a connection failure fails the SnapStart phase — initialization for the before-checkpoint hook, restore for the after-restore hook — rather than serving traffic against an improperly prepared application. The adapter does not impose its own deadline on a hook: Lambda already bounds both phases. The bound on the after-restore hook is not your function timeout — Lambda allows the whole Restore phase only 10 seconds, shared by the runtime load, the after-restore hook, and the readiness check that follows it, and overrunning it fails the restore with Lambda.SnapStartTimeoutException. Keep that in mind when a hook does slow work such as draining a large connection pool. The final readiness check runs on every restore (whether or not an after-restore path is configured). By default this readiness wait is unbounded; set AWS_LWA_READINESS_CHECK_TIMEOUT_SECONDS (fractional seconds allowed, e.g. 0.5) to bound it, in which case a restore whose application does not report ready within that timeout fails — a value above the 10-second Restore limit cannot take effect on a restore, since Lambda times the phase out first. The same variable also bounds the initial cold-start readiness check, which under SnapStart is what guarantees the application is ready before the snapshot: when set and the application does not report ready within the timeout, initialization fails (the Lambda runtime never starts) rather than snapshotting or serving an app that never came up.
Why you need the hooks
State captured in a snapshot is shared across every restored environment. Two classes of problem follow:
- Stale connections. Database connections, cached DNS, and keep-alive HTTP connections captured in the snapshot are dead by the time the environment is restored. Close them in the before-checkpoint hook and re-establish them in the after-restore hook.
- Uniqueness and entropy. Values seeded once at initialization — random number generators, UUID seeds, security tokens — become identical across every restored environment. Reseed them in the after-restore hook.
Securing the hook paths
The hook paths are control-plane operations. External requests (via API Gateway or ALB) that target a configured hook path receive 403 Forbidden and are never forwarded to your application. The guard matches the hook route strictly: it canonicalizes both the configured path and the incoming request path (percent-decoding, collapsing //, . and .. segments, and comparing case-insensitively) before comparing, so alternate spellings that resolve to the same route are blocked too. Choose paths your normal application traffic does not use (for example, /snapstart/before and /snapstart/after).
Three kinds of value are rejected at startup, because the adapter cannot guard the route they name. In each case initialization fails with an error naming the offending path, rather than running with a state-mutating route left reachable:
- A path whose decoded form contains a percent sign (for example
/snapstart/after%25, which decodes to/snapstart/after%), or a malformed%escape (a trailing%, or%zz). Web frameworks disagree on how to route these — some reject them outright, others decode them leniently — so the adapter cannot guarantee it blocks every spelling that reaches the route, and a partially protected hook path is worse than an obviously invalid one. Percent-encoding that decodes to an ordinary path is fine (/snapstart/%61fteris accepted and guarded as/snapstart/after), but a plain unencoded path is clearest. - A path that collapses to the application root (
/,//,/..,/.,/foo/..,/%2f, …). Guarding the root would return403for every request to/, so the guard cannot cover it — and the hook would stillPOSTto/on every lifecycle event, failing the phase on any application that does not handlePOST /. Use a dedicated path instead. - A path that resolves to the same route as
AWS_LWA_PASS_THROUGH_PATH(default/events). Non-HTTP trigger events are rewritten onto the pass-through path before the guard runs, so every such event would be answered with403instead of reaching your application.
Leaving a hook variable unset (or empty) is different from either: it simply means that hook does not fire.
Warning: this 403 guard exists only when the adapter is in the request path — i.e. when your app runs on Lambda behind the adapter. The hook routes are ordinary application routes that mutate state (the examples close and re-establish the connection pool), so if you run the same image or app without the adapter (Amazon ECS, Amazon EKS, a local Docker host), those routes are reachable and unauthenticated. In that case, do not expose them publicly, or protect them yourself.
Example
from fastapi import FastAPI, Response
app = FastAPI()
pool = None # your database/connection pool
@app.post("/snapstart/before")
async def before_checkpoint():
# Close resources that won't survive the snapshot.
if pool is not None:
await pool.close()
return Response(status_code=200)
@app.post("/snapstart/after")
async def after_restore():
# Re-establish resources and reseed anything that must be unique.
global pool
pool = await create_pool()
return Response(status_code=200)
Configure the function with:
AWS_LWA_SNAPSTART_BEFORE_CHECKPOINT_PATH=/snapstart/before
AWS_LWA_SNAPSTART_AFTER_RESTORE_PATH=/snapstart/after
For complete, deployable applications see the fastapi-snapstart-zip example (zip packaging) and the fastapi-snapstart example (container image).