This tutorial walks you through enabling Lambda SnapStart on a Python function end-to-end — publishing versions, implementing restore hooks for live resources, and then running AWS Lambda Power Tuning to find the optimal memory configuration. By the end you’ll have a function that avoids cold start penalties and is sized to the right memory setting for cost and latency.
Prerequisites
- AWS CLI v2 configured (
aws configure) - Python 3.12 Lambda function deployed (or we’ll create one)
- IAM permissions:
lambda:UpdateFunctionConfiguration,lambda:PublishVersion,lambda:CreateAlias,lambda:UpdateAlias,states:StartExecution,states:DescribeExecution - AWS SAM CLI installed (optional, but useful)
Step 1: Deploy a Sample Function
If you don’t have an existing function, create one that has a non-trivial init path so we can actually see SnapStart help:
mkdir snapstart-demo && cd snapstart-demo
cat > app.py << 'EOF'
import boto3
import json
import time
print(f"[INIT] Starting initialization at {time.time()}")
dynamodb = boto3.resource("dynamodb")
ssm = boto3.client("ssm")
init_time = time.time()
print(f"[INIT] Done at {init_time}")
def handler(event, context):
return {
"statusCode": 200,
"body": json.dumps({
"message": "Hello from SnapStart demo",
"remaining_ms": context.get_remaining_time_in_millis()
})
}
EOF
zip function.zip app.py
aws lambda create-function \
--function-name snapstart-demo \
--runtime python3.12 \
--role arn:aws:iam::YOUR_ACCOUNT:role/lambda-basic-role \
--handler app.handler \
--zip-file fileb://function.zip \
--memory-size 512
Step 2: Enable SnapStart and Publish a Version
aws lambda update-function-configuration \
--function-name snapstart-demo \
--snap-start ApplyOn=PublishedVersions
aws lambda wait function-updated --function-name snapstart-demo
VERSION=$(aws lambda publish-version \
--function-name snapstart-demo \
--query 'Version' \
--output text)
echo "Published version: $VERSION"
aws lambda create-alias \
--function-name snapstart-demo \
--name live \
--function-version $VERSION \
|| aws lambda update-alias \
--function-name snapstart-demo \
--name live \
--function-version $VERSION
Lambda takes a snapshot of the initialized environment when you publish the version. This happens once per publish, not per invocation. You’ll see [INIT] log lines exactly once during publish — subsequent cold starts restore from the snapshot instead.

Step 3: Implement a Restore Hook for Live Resources
import boto3
import json
import time
import os
print(f"[INIT] Initializing at {time.time()}")
ssm_client = boto3.client("ssm")
_config = None
def _load_config():
global _config
if _config is None:
resp = ssm_client.get_parameter(Name="/snapstart-demo/config")
_config = json.loads(resp["Parameter"]["Value"])
return _config
def __restore_hook__():
global ssm_client, _config
print(f"[RESTORE] Restoring at {time.time()}")
ssm_client = boto3.client("ssm")
_config = None
print("[RESTORE] Done")
def handler(event, context):
config = _load_config()
return {
"statusCode": 200,
"body": json.dumps({"message": "ok", "config_loaded": bool(config)})
}
Step 4: Install and Run Lambda Power Tuning
aws serverlessrepo create-cloud-formation-change-set \
--application-id arn:aws:serverlessrepo:us-east-1:451282441545:applications/aws-lambda-power-tuning \
--semantic-version 4.3.4 \
--stack-name lambda-power-tuning \
--capabilities CAPABILITY_IAM \
--region us-east-1
CHANGE_SET=$(aws serverlessrepo create-cloud-formation-change-set \
--application-id arn:aws:serverlessrepo:us-east-1:451282441545:applications/aws-lambda-power-tuning \
--semantic-version 4.3.4 \
--stack-name lambda-power-tuning \
--capabilities CAPABILITY_IAM \
--query 'ChangeSetId' --output text)
aws cloudformation execute-change-set --change-set-name $CHANGE_SET
aws cloudformation wait stack-create-complete --stack-name lambda-power-tuning
Once deployed, run Power Tuning against your function alias:
SM_ARN=$(aws cloudformation describe-stacks \
--stack-name lambda-power-tuning \
--query "Stacks[0].Outputs[?OutputKey=='StateMachineARN'].OutputValue" \
--output text)
EXEC_ARN=$(aws stepfunctions start-execution \
--state-machine-arn $SM_ARN \
--input '{
"lambdaARN": "arn:aws:lambda:us-east-1:YOUR_ACCOUNT:function:snapstart-demo:live",
"powerValues": [128, 256, 512, 1024, 2048, 3008],
"num": 50,
"payload": "{}",
"parallelInvocation": true,
"strategy": "balanced"
}' \
--query 'executionArn' --output text)
echo "Execution: $EXEC_ARN"
Step 5: Read the Results
aws stepfunctions describe-execution \
--execution-arn $EXEC_ARN \
--query 'status'
aws stepfunctions describe-execution \
--execution-arn $EXEC_ARN \
--query 'output' | python3 -m json.tool
The output includes a visualization URL — paste it into your browser to get the cost/performance chart. You’re looking for the memory setting where adding more RAM stops meaningfully reducing duration. Often it’s not the highest value. Lambda allocates CPU proportionally to memory, so the curve usually flattens at some middle point. Pick the “balanced” recommendation and update your function:
aws lambda update-function-configuration \
--function-name snapstart-demo \
--memory-size 1024
aws lambda publish-version --function-name snapstart-demo
Wrap-Up
At this point your function has SnapStart enabled, a restore hook handling live resources, and a memory configuration tuned by actual invocation data. That’s the complete optimization loop — and it took a couple of hours, not a rewrite.
At Enkompass (https://enkompass.net), this is our home turf. We build event-driven, serverless systems that scale to zero and bill like it. If you’d rather have seasoned cloud people handle it instead of learning the hard way at 2 AM, let’s talk. Reach out through our contact page or call us directly at +1-828-436-5667 — we’ll help you turn this from a someday-project into a done-deal.
