Idempotency utility for AWS Lambda functions that prevents duplicate executions by tracking request payloads in DynamoDB or cache stores, with support for function wrappers, decorators, and Middy middleware.
npx @tessl/cli install tessl/npm-aws-lambda-powertools--idempotency@2.29.0The idempotency package provides utilities to make AWS Lambda functions and arbitrary functions idempotent and safe to retry. It prevents duplicate executions by tracking request payloads in persistence stores like DynamoDB or Redis/Valkey.
npm install @aws-lambda-powertools/idempotency @aws-sdk/client-dynamodb @aws-sdk/lib-dynamodbimport { makeIdempotent, idempotent, IdempotencyConfig } from '@aws-lambda-powertools/idempotency';
import { DynamoDBPersistenceLayer } from '@aws-lambda-powertools/idempotency/dynamodb';
import { CachePersistenceLayer } from '@aws-lambda-powertools/idempotency/cache';
import { makeHandlerIdempotent } from '@aws-lambda-powertools/idempotency/middleware';For CommonJS:
const { makeIdempotent, idempotent, IdempotencyConfig } = require('@aws-lambda-powertools/idempotency');
const { DynamoDBPersistenceLayer } = require('@aws-lambda-powertools/idempotency/dynamodb');
const { CachePersistenceLayer } = require('@aws-lambda-powertools/idempotency/cache');
const { makeHandlerIdempotent } = require('@aws-lambda-powertools/idempotency/middleware');import { makeIdempotent } from '@aws-lambda-powertools/idempotency';
import { DynamoDBPersistenceLayer } from '@aws-lambda-powertools/idempotency/dynamodb';
import type { Context, APIGatewayProxyEvent } from 'aws-lambda';
// Create a persistence store
const persistenceStore = new DynamoDBPersistenceLayer({
tableName: 'idempotencyTable',
});
// Make your Lambda handler idempotent
const myHandler = async (
event: APIGatewayProxyEvent,
context: Context
): Promise<{ statusCode: number; body: string }> => {
// Your business logic here
return {
statusCode: 200,
body: JSON.stringify({ message: 'Success' }),
};
};
export const handler = makeIdempotent(myHandler, { persistenceStore });The idempotency package is built around several key components:
makeIdempotent), decorators (@idempotent), and Middy middleware (makeHandlerIdempotent)IdempotencyConfig class for fine-tuning behavior including JMESPath expressions, caching, expiry, and validationIdempotencyRecord class tracks execution state (INPROGRESS, COMPLETED, EXPIRED) with automatic expiry handlingMake any function idempotent using the makeIdempotent higher-order function. Works with Lambda handlers and arbitrary functions.
function makeIdempotent<Func extends AnyFunction>(
fn: Func,
options: ItempotentFunctionOptions<Parameters<Func>>
): (...args: Parameters<Func>) => ReturnType<Func>;
type ItempotentFunctionOptions<T extends Array<any>> = T[1] extends Context
? IdempotencyLambdaHandlerOptions
: IdempotencyLambdaHandlerOptions & {
dataIndexArgument?: number;
};
interface IdempotencyLambdaHandlerOptions {
persistenceStore: BasePersistenceLayer;
config?: IdempotencyConfig;
keyPrefix?: string;
}Use the @idempotent decorator to make class methods idempotent. Ideal for TypeScript class-based Lambda handlers.
function idempotent(
options: ItempotentFunctionOptions<Parameters<AnyFunction>>
): (
target: unknown,
propertyKey: string,
descriptor: PropertyDescriptor
) => PropertyDescriptor;Integrate idempotency with Middy middleware framework for Lambda handlers.
function makeHandlerIdempotent(
options: IdempotencyLambdaHandlerOptions
): MiddlewareLikeObj;
interface MiddlewareLikeObj {
before: (request: MiddyLikeRequest) => unknown;
after: (request: MiddyLikeRequest) => Promise<void>;
onError: (request: MiddyLikeRequest) => Promise<void>;
}Store idempotency records in Amazon DynamoDB with extensive configuration options for table attributes and behavior.
class DynamoDBPersistenceLayer extends BasePersistenceLayer {
constructor(config: DynamoDBPersistenceOptions);
}
interface DynamoDBPersistenceOptions {
tableName: string;
keyAttr?: string;
sortKeyAttr?: string;
staticPkValue?: string;
statusAttr?: string;
expiryAttr?: string;
inProgressExpiryAttr?: string;
dataAttr?: string;
validationKeyAttr?: string;
awsSdkV3Client?: DynamoDBClient;
clientConfig?: DynamoDBClientConfig;
}Store idempotency records in Redis or Valkey cache stores for high-performance scenarios.
class CachePersistenceLayer extends BasePersistenceLayer {
constructor(options: CachePersistenceOptions);
}
interface CachePersistenceOptions extends BasePersistenceAttributes {
client: CacheClient;
}
interface CacheClient {
get(name: string): Promise<CacheValue | null>;
set(name: CacheValue, value: unknown, options?: unknown): Promise<CacheValue | null>;
del(keys: string[]): Promise<number>;
}Customize idempotency behavior with the IdempotencyConfig class, including JMESPath expressions, caching, expiry, hash functions, and payload validation.
class IdempotencyConfig {
constructor(config: IdempotencyConfigOptions);
public eventKeyJmesPath: string;
public expiresAfterSeconds: number;
public hashFunction: string;
public jmesPathOptions: JMESPathParsingOptions;
public lambdaContext?: Context;
public maxLocalCacheSize: number;
public payloadValidationJmesPath?: string;
public throwOnNoIdempotencyKey: boolean;
public responseHook?: ResponseHook;
public useLocalCache: boolean;
public isEnabled(): boolean;
public registerLambdaContext(context: Context): void;
}
interface IdempotencyConfigOptions {
eventKeyJmesPath?: string;
payloadValidationJmesPath?: string;
jmesPathOptions?: Functions;
throwOnNoIdempotencyKey?: boolean;
expiresAfterSeconds?: number;
useLocalCache?: boolean;
maxLocalCacheSize?: number;
hashFunction?: string;
lambdaContext?: Context;
responseHook?: ResponseHook;
}Comprehensive error types for handling different idempotency failure scenarios.
class IdempotencyUnknownError extends Error {}
class IdempotencyItemAlreadyExistsError extends IdempotencyUnknownError {
public existingRecord?: IdempotencyRecord;
}
class IdempotencyItemNotFoundError extends IdempotencyUnknownError {}
class IdempotencyAlreadyInProgressError extends IdempotencyUnknownError {
public existingRecord?: IdempotencyRecord;
}
class IdempotencyInvalidStatusError extends IdempotencyUnknownError {}
class IdempotencyValidationError extends IdempotencyUnknownError {
public existingRecord?: IdempotencyRecord;
}
class IdempotencyInconsistentStateError extends IdempotencyUnknownError {}
class IdempotencyPersistenceLayerError extends IdempotencyUnknownError {}
class IdempotencyKeyError extends IdempotencyUnknownError {}Note: IdempotencyPersistenceConsistencyError is used internally by the cache persistence layer but is not exported from the main package.
Core type definitions for idempotency options, persistence configuration, and record management.
const IdempotencyRecordStatus: {
readonly INPROGRESS: "INPROGRESS";
readonly COMPLETED: "COMPLETED";
readonly EXPIRED: "EXPIRED";
};
const PERSISTENCE_ATTRIBUTE_KEY_MAPPINGS: {
readonly statusAttr: "status";
readonly expiryAttr: "expiration";
readonly inProgressExpiryAttr: "in_progress_expiration";
readonly dataAttr: "data";
readonly validationKeyAttr: "validation";
};