DynamoDB Triggers with Lambda: Setup, Examples and Retries

Written by Daniel Galati
Last updated: October 23rd, 2026
A DynamoDB trigger is a Lambda event source mapping that reads a table's DynamoDB Stream and invokes a function with batches of item changes. It runs after the database write succeeds, so it cannot reject or roll back that write. Lambda can deliver a record more than once; reliable triggers combine idempotent processing, bounded retries and a recovery destination.
What runs when an item changes?
The stream captures INSERT, MODIFY and REMOVE events. Lambda polls the stream, batches records, invokes your function and advances its checkpoint after successful processing. The writer does not wait for the function. A write that leaves the item unchanged produces no stream record.
Use triggers for notifications, search indexing, audit exports and derived data. Validate a write in the application or with a DynamoDB condition expression when it must be rejected before storage. See how DynamoDB Streams work for shard behavior, record retention and the full event format.
Enable the stream and prepare permissions
Choose a stream view that contains the data your handler needs:
| View | Data available to the handler |
|---|---|
KEYS_ONLY | Primary key attributes |
NEW_IMAGE | Item after an insert or update |
OLD_IMAGE | Item before an update or deletion |
NEW_AND_OLD_IMAGES | Both versions when applicable |
An insert never has an old image; a delete never has a new one. A MODIFY record contains both only when you selected both. The examples use a People table with a string partition key named PersonId.
For a table without an active stream:
Use the table's Region for every command. Changing a view requires replacing the stream, which changes its ARN; reconnect mappings and stream policies afterward.
The function's execution role needs dynamodb:DescribeStream, dynamodb:GetShardIterator, dynamodb:GetRecords and dynamodb:ListStreams, plus CloudWatch Logs access. The AWS managed policy AWSLambdaDynamoDBExecutionRole supplies baseline permissions; a custom policy can restrict stream actions to the intended resource. These are runtime permissions, separate from the deployment identity's permission to create mappings and pass the execution role.
If your handler calls another service, grant that operation separately. A failure queue requires sqs:SendMessage on its ARN. An S3 failure destination requires bucket/object permissions and, with a customer managed key, the applicable KMS permission.
Create the Lambda trigger
Create a function named people-stream-handler, using nodejs24.x for the JavaScript example below or python3.13 for Python. Package the handler and its dependencies, and configure the execution role before adding the trigger.
In the Lambda console, open the function, choose Add trigger, select DynamoDB and the table, and configure the starting position and batch settings. Review the advanced retry and failure settings rather than accepting unlimited retries automatically.
The equivalent AWS CLI v2 command uses an existing standard SQS queue for failure metadata. Replace its example account ID and Region:
These retry and age values are example operating choices, not universal defaults. Keep the mapping UUID from the response. Use get-event-source-mapping --uuid to inspect status and update-event-source-mapping --uuid to change it.
CloudFormation setup
This deployable template creates a table, log-only Python function, role, failure queue and mapping. Replace the inline handler with your packaged business logic for a real service:
AWS CDK with Python
Within a CDK v2 application, this alternative creates the same relationship. Put the Python handler shown below in lambda/people/index.py and package its dependencies in that asset directory:
Event source mapping settings
| Setting | Default or supported range | Practical effect |
|---|---|---|
BatchSize | Default 100; up to 10,000 records | Invocation payload also cannot exceed 6 MB, including record metadata |
MaximumBatchingWindowInSeconds | Default 0; up to 300 seconds | Trades lower invocation count for additional delay |
StartingPosition | TRIM_HORIZON or LATEST | Oldest retained records or newly arriving records |
ParallelizationFactor | Default 1; up to 10 | Concurrent batches per shard, with ordering preserved for each item's changes |
MaximumRetryAttempts | Default -1; configurable retry cap | Prevents a permanently failing invocation from blocking progress indefinitely |
MaximumRecordAgeInSeconds | Default -1; configurable age cap | Discards records that are too old; does not extend stream retention |
BisectBatchOnFunctionError | Default false | Splits failed batches to isolate a problematic record |
FunctionResponseTypes | Enable ReportBatchItemFailures | Allows the handler to identify the first failed sequence number |
DestinationConfig | No destination by default | Sends discarded-invocation details to a recovery destination |
FilterCriteria | No filtering by default | Removes unwanted records before invocation |
Enabled | Default true | Pauses or resumes polling without deleting the mapping |
AWS documents the mapping parameters separately from general Lambda asynchronous invocation options. Configure retry handling on the mapping, not just a function-level asynchronous dead-letter queue.
TRIM_HORIZON is usually the safer initial position: mapping creation can take time, and LATEST can miss writes during that startup interval. The new DynamoDB Streams timestamp-start capability is available to supported stream readers, but the Lambda DynamoDB mapping documentation still lists TRIM_HORIZON and LATEST. Do not assume every consumer accepts AT_TIMESTAMP.
Handle inserts, updates, deletes and TTL
This abbreviated insert event keeps Keys and NewImage consistent:
For a name update, eventName becomes MODIFY, OldImage.FirstName.S is John, and NewImage.FirstName.S is James. For deletion, eventName is REMOVE and only the old image is present. All events retain the key attributes.
JavaScript handler using SDK v3
Save as index.mjs, with handler index.handler, and bundle @aws-sdk/util-dynamodb. This handler logs the insert, name change or deletion and stops at the first failed record. Replace the log operation with an awaited, idempotent side effect:
This example logs names to demonstrate the images. In production, log event IDs and approved diagnostic fields rather than personal data or complete item images. SDK v3 replaces the unsupported aws-sdk v2 package.
Python handler with boto3
Boto3's TypeDeserializer converts DynamoDB JSON values; numeric attributes become Decimal. This version handles the same event types:
TTL deletes
A TTL expiration produces a REMOVE event with userIdentity.type equal to Service and userIdentity.principalId equal to dynamodb.amazonaws.com. Use those fields to distinguish expiration from an application delete. On global tables, only the Region that performed expiration marks the event this way. TTL deletion is asynchronous, typically within a few days; it is not a precise scheduler. See DynamoDB TTL.
Filter events before invoking Lambda
For a function that handles only inserts, save this object as filters.json:
To match a particular new name, the pattern itself would be:
Put that pattern into the mapping's string-valued Pattern field. Filtering uses DynamoDB's typed representation, not the plain objects produced by unmarshall. Numeric filter operators do not work on DynamoDB number strings. Filters cannot compare old and new values dynamically; compare them in your handler when you need a transition check.
Unmatched records are skipped, not saved for later. Changing a filter does not rewind a mapping. AWS's DynamoDB event filtering documentation covers the supported pattern structure.
Retries, partial batches and recovery
Without partial responses, throwing an error retries the whole batch, including records that already succeeded. With ReportBatchItemFailures, return the failed record's sequence number, not eventID. Lambda resumes from the lowest failed sequence number. Both handlers stop at the first failure so they do not perform later work that would immediately be replayed.
Bisecting helps isolate invocation failures; splitting a batch does not consume the retry quota. Retry-count limits apply to errors returned by an invoked function. Pre-invocation failures, such as throttling, are governed by record age and retention rather than that same function-error retry count.
When retry or age limits are reached, Lambda discards records and advances. A standard SQS or SNS failure destination receives invocation metadata and stream sequence information, not the full original batch. Recover those records before the stream's 24-hour retention expires. An S3 destination retains the full invocation payload, which supports later investigation and replay. Follow the failure-destination configuration and monitor delivery failures too.
Make downstream operations idempotent. For a database projection, store and conditionally compare a business version. For an external API, pass a stable idempotency key supported by that API. Merely recording an event ID before sending a notification can lose the notification if the function crashes between those steps.
Cross-account triggers, scaling and monitoring
Lambda supports a DynamoDB stream in another account through a resource-based policy on that stream. The function and stream must still be in the same Region. Grant the function execution role stream-read permission in its own account and allow that role in the stream policy. Follow AWS's cross-account Lambda setup. Recreated streams need a policy on their new ARN.
Design for up to two readers per shard on a single-Region table; AWS recommends one for global tables. Multiple mappings do not provide unlimited fan-out. Use one consumer to publish notifications through SNS, or use Kinesis Data Streams when the consumer requirements justify it.
Monitor IteratorAge, Lambda errors, duration, throttles and destination-delivery failures. Rising iterator age means processing is falling behind; investigate failures and downstream latency before raising concurrency. Avoid writing back to the source item without a filter or condition that prevents an invocation loop.
Standard Lambda trigger reads from DynamoDB Streams are free, while Lambda execution and downstream services are billed. Lambda Managed Instances are an exception to that free stream-read treatment. Test replayed records, missing images, malformed attributes, permission failures and a deliberately failing record before enabling production traffic.
Frequently Asked Questions
Does DynamoDB have triggers?
Can DynamoDB trigger Step Functions?
Can I configure multiple DynamoDB triggers?
Why is my DynamoDB trigger processing records twice?
Can a Lambda function read a DynamoDB stream in another account?
Why is my trigger not receiving updates?
Dynobase is a Professional GUI Client for DynamoDB
Start your 7-day free trial today