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