AWS Lambda durable functions
Build resilient multi-step applications and AI workflows that can execute for up to 1 year while maintaining reliable progress despite interruptions.
Works best with the AWS MCP server but is not required. All AWS interactions in this skill use standard AWS CLI commands that work in any environment with configured AWS credentials.
Critical Rules
Read these before writing any code. Each one is a constraint that will silently break a function if violated.
- Durable execution must be enabled at function creation time — it cannot be retrofitted. A new Lambda function must be created with durable execution turned on. Migrate the logic into the new function; do not attempt to install the SDK and wrap the handler of the existing function and expect it to work.
- Durable functions must be invoked with a qualified ARN — a specific version, an alias, or the literal
$LATEST suffix. An unqualified function name will fail. See the Invocation Requirements section below for examples.
- Durable operations cannot be nested. You cannot call
context.step(), context.wait(), or context.invoke() from inside another step's callback. Use context.runInChildContext() to group operations instead.
- All non-deterministic code must run inside steps.
Date.now(), Math.random(), UUID generation, API calls, and database queries outside a step will produce different values on replay and corrupt execution state.
- Closure mutations are lost on replay - return values from steps
- Side effects outside steps repeat - use
context.logger (replay-aware)
When to Load Reference Files
Load the appropriate reference file based on what the user is working on:
- Getting started, basic setup, example, ESLint, or Jest setup -> see getting-started.md
- Understanding replay model, determinism, or non-deterministic errors -> see replay-model-rules.md
- Creating steps, atomic operations, or retry logic -> see step-operations.md
- Waiting, delays, callbacks, external systems, or polling -> see wait-operations.md
- Parallel execution, map operations, batch processing, or concurrency -> see concurrent-operations.md
- Error handling, retry strategies, saga pattern, or compensating transactions -> see error-handling.md
- Advanced error handling, timeout handling, circuit breakers, or conditional retries -> see advanced-error-handling.md
- Testing, local testing, cloud testing, test runner, or flaky tests -> see testing-patterns.md
- Deployment, CloudFormation, CDK, SAM, log groups, deploy, or infrastructure -> see deployment-iac.md
- Advanced patterns, GenAI agents, completion policies, step semantics, or custom serialization -> see advanced-patterns.md
- troubleshooting, stuck execution, failed execution, debug execution ID, execution history, execution error, why did my execution fail, execution timed out, callback not received, diagnose execution, or root cause execution -> see troubleshooting-executions.md
Quick Reference
Basic Handler Pattern
TypeScript:
import { withDurableExecution, DurableContext } from '@aws/durable-execution-sdk-js';
export const handler = withDurableExecution(async (event, context: DurableContext) => {
const result = await context.step('process', async () => processData(event));
return result;
});
Python:
from aws_durable_execution_sdk_python import durable_execution, DurableContext
@durable_execution
def handler(event: dict, context: DurableContext) -> dict:
result = context.step(lambda _: process_data(event), name='process')
return result
Python API Differences
The Python SDK differs from TypeScript in several key areas:
- Steps: Use
@durable_step decorator + context.step(my_step(args)), or inline context.step(lambda _: ..., name='...'). Prefer the decorator for automatic step naming.
- Wait:
context.wait(duration=Duration.from_seconds(n), name='...')
- Exceptions:
ExecutionError (permanent), InvocationError (transient), CallbackError (callback failures)
- Testing: Use
DurableFunctionTestRunner class directly - instantiate with handler, use context manager, call run(input=...)
Invocation Requirements
Durable functions require qualified ARNs (version, alias, or $LATEST):
# Valid
aws lambda invoke --function-name my-function:1 output.json
aws lambda invoke --function-name my-function:live output.json
# Invalid - will fail
aws lambda invoke --function-name my-function output.json
IAM Permissions
Your Lambda execution role MUST have the AWSLambdaBasicDurableExecutionRolePolicy managed policy attached. This includes:
lambda:CheckpointDurableExecution - Persist execution state
lambda:GetDurableExecutionState - Retrieve execution state
- CloudWatch Logs permissions
Additional permissions needed for:
- Durable invokes:
lambda:InvokeFunction on target function ARNs
- External callbacks: Systems need
lambda:SendDurableExecutionCallbackSuccess and lambda:SendDurableExecutionCallbackFailure
Validation Guidelines
When writing or reviewing durable function code, ALWAYS check for these replay model violations:
- Non-deterministic code outside steps:
Date.now(), Math.random(), UUID generation, API calls, database queries must all be inside steps
- Nested durable operations in step functions: Cannot call
context.step(), context.wait(), or context.invoke() inside a step function — use context.runInChildContext() instead
- Closure mutations that won't persist: Variables mutated inside steps are NOT preserved across replays — return values from steps instead
- Side effects outside steps that repeat on replay: Use
context.logger for logging (it is replay-aware and deduplicates automatically)
When implementing or modifying tests for durable functions, ALWAYS verify:
- All operations have descriptive names
- Tests get operations by NAME, never by index
- Replay behavior is tested with multiple invocations
- Use
LocalDurableTestRunner for local testing
Security Considerations
- Checkpoint data encryption: Execution state is persisted automatically. Enable KMS encryption on associated CloudWatch Log Groups to protect checkpointed data at rest.
- Sensitive data in step results: Step return values are checkpointed and persisted. Do not return secrets, raw credentials, or PII from steps — store sensitive data in Secrets Manager or SSM Parameter Store and return references instead.
- Input validation: Validate and sanitize event payloads at the handler entry point before passing data to steps.
- Credential management: Retrieve secrets from AWS Secrets Manager or SSM Parameter Store within steps.
- Callback payload validation: Data received via
waitForCallback originates from external systems — validate and sanitize before processing.
- Logging: Avoid
DEBUG log level in non-development environments as it may expose step results and execution state. Enable CloudWatch Logs encryption with KMS.
Resources
1---2name: aws-lambda-durable-functions3description: Builds resilient, long-running, multi-step applications with AWS Lambda durable functions with automatic state persistence, retry logic, and orchestration for long-running executions. Covers the critical replay model, step operations, wait/callback patterns, error handling with saga pattern, testing with LocalDurableTestRunner. Triggers on phrases like lambda durable functions, durable execution, workflow orchestration, state machines, retry/checkpoint patterns, long-running stateful Lambda functions, saga pattern, human-in-the-loop callbacks, reliable serverless applications, context.step, context.wait, context.invoke, context.runInChildContext, withDurableExecution, DurableContext, UnrecoverableInvocationError, durable-execution-sdk, qualified ARN invocation, and durable handler replay.4---5
6# AWS Lambda durable functions
7
8Build resilient multi-step applications and AI workflows that can execute for up to 1 year while maintaining reliable progress despite interruptions.
9
10**Works best with** the [AWS MCP server](https://docs.aws.amazon.com/aws-mcp/) but is not required. All AWS interactions in this skill use standard AWS CLI commands that work in any environment with configured AWS credentials.
11
12## Critical Rules
13
14Read these before writing any code. Each one is a constraint that will silently break a function if violated.
15
161. **Durable execution must be enabled at function creation time — it cannot be retrofitted.** A new Lambda function must be created with durable execution turned on. Migrate the logic into the new function; do not attempt to install the SDK and wrap the handler of the existing function and expect it to work.
172. **Durable functions must be invoked with a qualified ARN** — a specific version, an alias, or the literal `$LATEST` suffix. An unqualified function name will fail. See the *Invocation Requirements* section below for examples.
183. **Durable operations cannot be nested.** You cannot call `context.step()`, `context.wait()`, or `context.invoke()` from inside another step's callback. Use `context.runInChildContext()` to group operations instead.
194. **All non-deterministic code must run inside steps.** `Date.now()`, `Math.random()`, UUID generation, API calls, and database queries outside a step will produce different values on replay and corrupt execution state.
205. **Closure mutations are lost on replay** - return values from steps
216. **Side effects outside steps repeat** - use `context.logger` (replay-aware)
22
23## When to Load Reference Files
24
25Load the appropriate reference file based on what the user is working on:
26
27- **Getting started**, **basic setup**, **example**, **ESLint**, or **Jest setup** -> see [getting-started.md](references/getting-started.md)
28- **Understanding replay model**, **determinism**, or **non-deterministic errors** -> see [replay-model-rules.md](references/replay-model-rules.md)
29- **Creating steps**, **atomic operations**, or **retry logic** -> see [step-operations.md](references/step-operations.md)
30- **Waiting**, **delays**, **callbacks**, **external systems**, or **polling** -> see [wait-operations.md](references/wait-operations.md)
31- **Parallel execution**, **map operations**, **batch processing**, or **concurrency** -> see [concurrent-operations.md](references/concurrent-operations.md)
32- **Error handling**, **retry strategies**, **saga pattern**, or **compensating transactions** -> see [error-handling.md](references/error-handling.md)
33- **Advanced error handling**, **timeout handling**, **circuit breakers**, or **conditional retries** -> see [advanced-error-handling.md](references/advanced-error-handling.md)
34- **Testing**, **local testing**, **cloud testing**, **test runner**, or **flaky tests** -> see [testing-patterns.md](references/testing-patterns.md)
35- **Deployment**, **CloudFormation**, **CDK**, **SAM**, **log groups**, **deploy**, or **infrastructure** -> see [deployment-iac.md](references/deployment-iac.md)
36- **Advanced patterns**, **GenAI agents**, **completion policies**, **step semantics**, or **custom serialization** -> see [advanced-patterns.md](references/advanced-patterns.md)
37- **troubleshooting**, **stuck execution**, **failed execution**, **debug execution ID**, **execution history**, **execution error**, **why did my execution fail**, **execution timed out**, **callback not received**, **diagnose execution**, or **root cause execution** -> see [troubleshooting-executions.md](references/troubleshooting-executions.md)
38
39## Quick Reference
40
41### Basic Handler Pattern
42
43**TypeScript:**
44
45```typescript
46import { withDurableExecution, DurableContext } from '@aws/durable-execution-sdk-js';
47
48export const handler = withDurableExecution(async (event, context: DurableContext) => {
49 const result = await context.step('process', async () => processData(event));
50 return result;
51});
52```
53
54**Python:**
55
56```python
57from aws_durable_execution_sdk_python import durable_execution, DurableContext
58
59@durable_execution
60def handler(event: dict, context: DurableContext) -> dict:
61 result = context.step(lambda _: process_data(event), name='process')
62 return result
63```
64
65### Python API Differences
66
67The Python SDK differs from TypeScript in several key areas:
68
69- **Steps**: Use `@durable_step` decorator + `context.step(my_step(args))`, or inline `context.step(lambda _: ..., name='...')`. Prefer the decorator for automatic step naming.
70- **Wait**: `context.wait(duration=Duration.from_seconds(n), name='...')`
71- **Exceptions**: `ExecutionError` (permanent), `InvocationError` (transient), `CallbackError` (callback failures)
72- **Testing**: Use `DurableFunctionTestRunner` class directly - instantiate with handler, use context manager, call `run(input=...)`
73
74### Invocation Requirements
75
76Durable functions **require qualified ARNs** (version, alias, or `$LATEST`):
77
78```bash
79# Valid
80aws lambda invoke --function-name my-function:1 output.json
81aws lambda invoke --function-name my-function:live output.json
82
83# Invalid - will fail
84aws lambda invoke --function-name my-function output.json
85```
86
87## IAM Permissions
88
89Your Lambda execution role MUST have the `AWSLambdaBasicDurableExecutionRolePolicy` managed policy attached. This includes:
90
91- `lambda:CheckpointDurableExecution` - Persist execution state
92- `lambda:GetDurableExecutionState` - Retrieve execution state
93- CloudWatch Logs permissions
94
95**Additional permissions needed for:**
96
97- **Durable invokes**: `lambda:InvokeFunction` on target function ARNs
98- **External callbacks**: Systems need `lambda:SendDurableExecutionCallbackSuccess` and `lambda:SendDurableExecutionCallbackFailure`
99
100## Validation Guidelines
101
102When writing or reviewing durable function code, ALWAYS check for these replay model violations:
103
1041. **Non-deterministic code outside steps**: `Date.now()`, `Math.random()`, UUID generation, API calls, database queries must all be inside steps
1052. **Nested durable operations in step functions**: Cannot call `context.step()`, `context.wait()`, or `context.invoke()` inside a step function — use `context.runInChildContext()` instead
1063. **Closure mutations that won't persist**: Variables mutated inside steps are NOT preserved across replays — return values from steps instead
1074. **Side effects outside steps that repeat on replay**: Use `context.logger` for logging (it is replay-aware and deduplicates automatically)
108
109When implementing or modifying tests for durable functions, ALWAYS verify:
110
1111. All operations have descriptive names
1122. Tests get operations by NAME, never by index
1133. Replay behavior is tested with multiple invocations
1144. Use `LocalDurableTestRunner` for local testing
115
116## Security Considerations
117
118- **Checkpoint data encryption**: Execution state is persisted automatically. Enable KMS encryption on associated CloudWatch Log Groups to protect checkpointed data at rest.
119- **Sensitive data in step results**: Step return values are checkpointed and persisted. Do not return secrets, raw credentials, or PII from steps — store sensitive data in Secrets Manager or SSM Parameter Store and return references instead.
120- **Input validation**: Validate and sanitize event payloads at the handler entry point before passing data to steps.
121- **Credential management**: Retrieve secrets from AWS Secrets Manager or SSM Parameter Store within steps.
122- **Callback payload validation**: Data received via `waitForCallback` originates from external systems — validate and sanitize before processing.
123- **Logging**: Avoid `DEBUG` log level in non-development environments as it may expose step results and execution state. Enable CloudWatch Logs encryption with KMS.
124
125## Resources
126
127- [AWS Lambda durable functions Documentation](https://docs.aws.amazon.com/lambda/latest/dg/durable-functions.html)
128- [JavaScript SDK Repository](https://github.com/aws/aws-durable-execution-sdk-js)
129- [Python SDK Repository](https://github.com/aws/aws-durable-execution-sdk-python)
130- [IAM Policy Reference](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSLambdaBasicDurableExecutionRolePolicy.html)