The DynamoDBPersistenceLayer class provides DynamoDB-backed storage for idempotency records. It uses the AWS SDK for JavaScript v3 to read and write records with extensive configuration options.
Stores idempotency records in Amazon DynamoDB with customizable table configuration and attribute names.
/**
* DynamoDB persistence layer for idempotency records.
*
* Uses AWS SDK v3 to write and read idempotency records from DynamoDB.
* Supports both simple (single key) and composite (partition + sort key) table structures.
* Can use default client or bring your own configured client instance.
*
* @param config - Configuration options for DynamoDB persistence
*/
class DynamoDBPersistenceLayer extends BasePersistenceLayer {
constructor(config: DynamoDBPersistenceOptions);
}
type DynamoDBPersistenceOptions =
| DynamoDBPersistenceOptionsWithClientConfig
| DynamoDBPersistenceOptionsWithClientInstance;
interface DynamoDBPersistenceOptionsWithClientConfig {
/** DynamoDB table name (required) */
tableName: string;
/** Primary key attribute name (default: 'id') */
keyAttr?: string;
/** Sort key attribute name for composite keys (optional) */
sortKeyAttr?: string;
/** Static partition key value when using sort keys (default: 'idempotency#{LAMBDA_FUNCTION_NAME}') */
staticPkValue?: string;
/** Status attribute name (default: 'status') */
statusAttr?: string;
/** Expiry timestamp attribute name (default: 'expiration') */
expiryAttr?: string;
/** In-progress expiry timestamp attribute name (default: 'in_progress_expiration') */
inProgressExpiryAttr?: string;
/** Response data attribute name (default: 'data') */
dataAttr?: string;
/** Payload validation hash attribute name (default: 'validation') */
validationKeyAttr?: string;
/** Optional configuration for DynamoDB client initialization */
clientConfig?: DynamoDBClientConfig;
/** Must not be provided when using clientConfig */
awsSdkV3Client?: never;
}
interface DynamoDBPersistenceOptionsWithClientInstance {
tableName: string;
keyAttr?: string;
sortKeyAttr?: string;
staticPkValue?: string;
statusAttr?: string;
expiryAttr?: string;
inProgressExpiryAttr?: string;
dataAttr?: string;
validationKeyAttr?: string;
/** Optional AWS SDK v3 DynamoDBClient instance */
awsSdkV3Client?: DynamoDBClient;
/** Must not be provided when using awsSdkV3Client */
clientConfig?: never;
}Usage Examples:
Basic Setup with Default Configuration
import { DynamoDBPersistenceLayer } from '@aws-lambda-powertools/idempotency/dynamodb';
import { makeIdempotent } from '@aws-lambda-powertools/idempotency';
// Minimal configuration - uses default attribute names and creates a new client
const persistenceStore = new DynamoDBPersistenceLayer({
tableName: 'idempotencyTable',
});
const myHandler = async (event: any, context: any) => {
// Your logic
};
export const handler = makeIdempotent(myHandler, { persistenceStore });With Custom Attribute Names
import { DynamoDBPersistenceLayer } from '@aws-lambda-powertools/idempotency/dynamodb';
import { makeIdempotent } from '@aws-lambda-powertools/idempotency';
const persistenceStore = new DynamoDBPersistenceLayer({
tableName: 'idempotencyTable',
keyAttr: 'requestId', // Custom primary key attribute
statusAttr: 'requestStatus', // Custom status attribute
expiryAttr: 'ttl', // Custom expiry attribute
dataAttr: 'responseData', // Custom data attribute
validationKeyAttr: 'payloadHash', // Custom validation attribute
});
const myHandler = async (event: any, context: any) => {
// Your logic
};
export const handler = makeIdempotent(myHandler, { persistenceStore });With Client Configuration (AWS Region)
import { DynamoDBPersistenceLayer } from '@aws-lambda-powertools/idempotency/dynamodb';
import { makeIdempotent } from '@aws-lambda-powertools/idempotency';
// Specify AWS region and other client configuration
const persistenceStore = new DynamoDBPersistenceLayer({
tableName: 'idempotencyTable',
clientConfig: {
region: 'us-east-1',
},
});
const myHandler = async (event: any, context: any) => {
// Your logic
};
export const handler = makeIdempotent(myHandler, { persistenceStore });With Custom DynamoDB Client
import { DynamoDBPersistenceLayer } from '@aws-lambda-powertools/idempotency/dynamodb';
import { makeIdempotent } from '@aws-lambda-powertools/idempotency';
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
// Create and configure your own DynamoDB client
const dynamoDBClient = new DynamoDBClient({
region: 'us-west-2',
maxAttempts: 3,
requestHandler: {
// Custom configurations
},
});
const persistenceStore = new DynamoDBPersistenceLayer({
tableName: 'idempotencyTable',
awsSdkV3Client: dynamoDBClient,
});
const myHandler = async (event: any, context: any) => {
// Your logic
};
export const handler = makeIdempotent(myHandler, { persistenceStore });With Composite Key (Partition + Sort Key)
import { DynamoDBPersistenceLayer } from '@aws-lambda-powertools/idempotency/dynamodb';
import { makeIdempotent } from '@aws-lambda-powertools/idempotency';
// Use a table with both partition key and sort key
const persistenceStore = new DynamoDBPersistenceLayer({
tableName: 'idempotencyTable',
keyAttr: 'pk', // Partition key attribute
sortKeyAttr: 'sk', // Sort key attribute
staticPkValue: 'idempotency#my-function', // Static value for partition key
});
// With composite keys:
// - pk (partition key) = staticPkValue
// - sk (sort key) = hashed idempotency key
const myHandler = async (event: any, context: any) => {
// Your logic
};
export const handler = makeIdempotent(myHandler, { persistenceStore });Shared Table Pattern
import { DynamoDBPersistenceLayer } from '@aws-lambda-powertools/idempotency/dynamodb';
import { makeIdempotent } from '@aws-lambda-powertools/idempotency';
// Share a single DynamoDB table across multiple functions using sort keys
const persistenceStore = new DynamoDBPersistenceLayer({
tableName: 'shared-idempotency-table',
keyAttr: 'pk',
sortKeyAttr: 'sk',
staticPkValue: 'payment-service', // Unique prefix for this service
});
const myHandler = async (event: any, context: any) => {
// Your logic
};
export const handler = makeIdempotent(myHandler, { persistenceStore });When using only keyAttr (no sortKeyAttr):
{
"id": "my-function#a1b2c3d4...", // Hashed idempotency key
"status": "COMPLETED", // INPROGRESS | COMPLETED | EXPIRED
"expiration": 1234567890, // TTL in seconds (Unix epoch)
"in_progress_expiration": 1234567890000, // Lambda timeout in milliseconds
"data": { ... }, // Response data
"validation": "e5f6g7h8..." // Payload hash (if validation enabled)
}When using both keyAttr and sortKeyAttr:
{
"pk": "idempotency#my-function", // Static partition key value
"sk": "a1b2c3d4...", // Hashed idempotency key (sort key)
"status": "COMPLETED",
"expiration": 1234567890,
"in_progress_expiration": 1234567890000,
"data": { ... },
"validation": "e5f6g7h8..."
}Your Lambda function needs the following DynamoDB permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"dynamodb:GetItem",
"dynamodb:PutItem",
"dynamodb:UpdateItem",
"dynamodb:DeleteItem"
],
"Resource": "arn:aws:dynamodb:REGION:ACCOUNT_ID:table/TABLE_NAME"
}
]
}Enable TTL on the expiry attribute to automatically delete expired records:
expiryAttr (default: "expiration")Not required for basic idempotency functionality. The persistence layer uses GetItem and PutItem operations on the primary key.
The DynamoDB persistence layer uses conditional expressions to prevent race conditions:
IdempotencyItemAlreadyExistsError for active duplicatesIdempotencyItemNotFoundError - Record not found during retrievalIdempotencyItemAlreadyExistsError - Duplicate request detected with active recordsortKeyAttr equals keyAttr (invalid configuration)