Docs / Use Cases / Lambda Cold Starts

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.

What the demo does. Starts LocalEmu with 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

Terminal
$ 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

Terminal
$ 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)

Terminal
$ 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)

Terminal
$ 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)

Terminal
$ 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

Terminal
# 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

Terminal
$ 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

Terminal
# 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
Variable
Description
Default
LAMBDA_COLD_START_DELAY
Seconds of delay on first invocation. Set to 0 to disable.
0 (disabled)
LAMBDA_COLD_START_IDLE_TIMEOUT
Seconds of inactivity before a function goes cold again.
300 (5 min)
Provisioned concurrency
Skips the cold-start delay. Basic lifecycle supported; advanced allocation transitions are limited.
Automatic