Lambda Cold Starts
Reproduce AWS Lambda cold-start latency locally. The first invocation of a function (or the first one after an idle window) pays a configurable delay, subsequent invocations skip it. Each function version tracks its own warm state.
LAMBDA_COLD_START_DELAY=3,
creates a Lambda function, invokes it four times, then a second function
once, then both via the Python SDK. Each invocation is wrapped in
time so the first-call
delay and warm-call baseline are both observable. Numbers below were
captured on a single laptop run, the orders of magnitude are stable, the
exact milliseconds will vary with your hardware and the Lambda image
cache.
Cold Start Delay
First invocation pays the configured delay (e.g. 3s). Subsequent calls skip it until the function goes idle.
Per-Function Tracking
Each function tracks warm/cold state independently. Function A going cold doesn't affect Function B.
Idle Timeout
After 5 min of inactivity (configurable), the function goes cold again. Matches real AWS behavior.
Enable cold start simulation
$ LAMBDA_COLD_START_DELAY=3 localemu start
# Banner shows:
# Features: LAMBDA_COLD_START_DELAY=3.0
# Configure idle timeout (optional):
# LAMBDA_COLD_START_IDLE_TIMEOUT=300 (5 min default, matching AWS) LAMBDA_COLD_START_DELAY=3 adds a 3-second delay to the first invocation of each Lambda function. LAMBDA_COLD_START_IDLE_TIMEOUT=300 sets how long a function stays warm (default 5 min, matching AWS).
Create a Lambda function
$ awsemu lambda create-function \
--function-name cold-start-test \
--runtime python3.12 \
--handler lambda_function.lambda_handler \
--role arn:aws:iam::000000000000:role/lambda-role \
--zip-file fileb://function.zip \
--memory-size 256
{
"FunctionName": "cold-start-test",
"FunctionArn": "arn:aws:lambda:us-east-1:000000000000:function:cold-start-test",
"Runtime": "python3.12",
"MemorySize": 256,
"State": "Pending"
}
# Wait for Active state
$ awsemu lambda wait function-active-v2 \
--function-name cold-start-test Create a Python 3.12 Lambda function with 256MB memory. Wait for the function to reach Active state before invoking.
First invocation (cold start)
$ time awsemu lambda invoke \
--function-name cold-start-test \
--payload '{"action": "first-call"}' \
/tmp/response.json
{
"StatusCode": 200,
"ExecutedVersion": "$LATEST"
}
real 0m4.760s
user 0m0.190s
sys 0m0.042s
# Server log:
# Simulating cold start for arn:aws:lambda:us-east-1:000000000000:function:cold-start-test:$LATEST: sleeping 3.0s
$ cat /tmp/response.json
{"message": "Hello from Lambda!", "requestId": "ea8d26be-...", "functionName": "cold-start-test"} The first invocation sleeps for the configured
LAMBDA_COLD_START_DELAY seconds plus the container startup cost. The server log confirms the cold-start simulation fired. Exact wall time depends on your machine and the Lambda image state; the sample numbers above are illustrative.
Second invocation (warm)
$ time awsemu lambda invoke \
--function-name cold-start-test \
--payload '{"action": "second-call"}' \
/tmp/response.json
{
"StatusCode": 200,
"ExecutedVersion": "$LATEST"
}
real 0m0.280s
user 0m0.185s
sys 0m0.040s
# No cold start, function is warm
# 4.76s → 0.28s (17x faster) No cold start: the tracker sees the function as warm and skips the sleep. Container reuse and a no-op handler dominate the rest of the wall time (mostly CLI + HTTP overhead).
Third invocation (still warm)
$ time awsemu lambda invoke \
--function-name cold-start-test \
--payload '{"action": "third-call"}' \
/tmp/response.json
real 0m0.270s
# Consistent warm performance: 0.27s Consistent warm performance. Once warm, subsequent invocations stay fast until LAMBDA_COLD_START_IDLE_TIMEOUT elapses with no traffic.
Independent function tracking
# Create a second function
$ awsemu lambda create-function \
--function-name cold-start-test-2 \
--runtime python3.12 \
--handler lambda_function.lambda_handler \
--role arn:aws:iam::000000000000:role/lambda-role \
--zip-file fileb://function.zip \
--memory-size 256
$ awsemu lambda wait function-active-v2 \
--function-name cold-start-test-2
# Invoke function 2, cold start (each function tracks independently)
$ time awsemu lambda invoke \
--function-name cold-start-test-2 \
--payload '{"action": "first-call"}' \
/tmp/response2.json
real 0m3.950s
# Invoke function 1 again, still warm from earlier
$ time awsemu lambda invoke \
--function-name cold-start-test \
--payload '{"action": "fourth-call"}' \
/tmp/response.json
real 0m0.280s
# Cold/warm state is per-function, not global Function 2 gets its own cold start while Function 1 is still warm. Cold/warm state is per qualified function ARN, not global: the tracker keys on qualified_arn (function + version).
Python SDK timing
$ python3 -c "
import boto3, time
client = boto3.client(
'lambda',
endpoint_url='http://localhost:4566',
region_name='us-east-1'
)
# Both functions are warm from previous invocations
for name in ['cold-start-test', 'cold-start-test-2']:
start = time.monotonic()
client.invoke(
FunctionName=name,
Payload=b'{"action": "sdk-call"}'
)
elapsed = (time.monotonic() - start) * 1000
print(f'{name}: {elapsed:.0f}ms')
"
cold-start-test: 20ms
cold-start-test-2: 9ms
# After 5 min of inactivity (LAMBDA_COLD_START_IDLE_TIMEOUT),
# the function goes cold again and the next invocation gets the delay. Both functions are warm, Function 1: 20ms, Function 2: 9ms. After LAMBDA_COLD_START_IDLE_TIMEOUT (default 5 min), the function goes cold again.
How it works
ColdStartTracker
Thread-safe singleton tracking per-function-version warm/cold state using monotonic timestamps.
First caller wins
When concurrent requests hit a cold function, only the first gets the delay. It marks the function warm immediately so others proceed without waiting.
Idle timeout
After LAMBDA_COLD_START_IDLE_TIMEOUT (default 300s / 5min), the function goes cold again. Matches real AWS behavior.
Provisioned concurrency
Functions with provisioned concurrency skip the cold-start delay. Basic lifecycle is supported; advanced scenarios (allocation-status transitions, cross-version/alias routing) are limited, see known limitations.
Configuration
# Cold start delay in seconds (set to 0 to disable)
$ LAMBDA_COLD_START_DELAY=3 localemu start
# Idle timeout before going cold again (default 300s / 5 min)
$ LAMBDA_COLD_START_IDLE_TIMEOUT=300 localemu start
# Combine both
$ LAMBDA_COLD_START_DELAY=3 LAMBDA_COLD_START_IDLE_TIMEOUT=600 localemu start
# Provisioned concurrency automatically skips cold start
$ awsemu lambda put-provisioned-concurrency-config \
--function-name cold-start-test \
--qualifier \"$LATEST\" \
--provisioned-concurrent-executions 5