DynamoDB
Stream Trigger
AWS Lambda
Insert Only
Database Configuration

Configure DynamoDB stream trigger with insert only

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

A DynamoDB stream itself records multiple event types such as INSERT, MODIFY, and REMOVE; there is no table setting that makes the stream emit only inserts. If you want a Lambda trigger to react to inserts only, the right approach is to attach the stream normally and then filter for eventName == INSERT, either in Lambda event source filtering or inside the handler code.

What DynamoDB Streams Actually Emit

Once streams are enabled on a table, each record in the stream includes an event name that tells you what happened:

  • 'INSERT'
  • 'MODIFY'
  • 'REMOVE'

A simplified event record looks like this:

json
1{
2  "eventName": "INSERT",
3  "dynamodb": {
4    "Keys": {
5      "id": { "S": "123" }
6    },
7    "NewImage": {
8      "id": { "S": "123" },
9      "status": { "S": "NEW" }
10    }
11  }
12}

So the stream itself is general-purpose. Insert-only behavior is implemented on the consumer side.

Enable the Right Stream View

If your Lambda needs to inspect the inserted item, choose a stream view that includes the new item image.

Commonly that means NEW_IMAGE or NEW_AND_OLD_IMAGES.

From the AWS CLI:

bash
aws dynamodb update-table \
  --table-name Orders \
  --stream-specification StreamEnabled=true,StreamViewType=NEW_IMAGE

Without NEW_IMAGE, you may still know an insert occurred, but you will not have the full inserted item available in the event payload.

The Oldest and Most Portable Method: Filter in Code

The simplest approach is to let Lambda receive stream records and ignore anything that is not an insert.

python
1import json
2
3
4def lambda_handler(event, context):
5    for record in event.get("Records", []):
6        if record.get("eventName") != "INSERT":
7            continue
8
9        new_item = record["dynamodb"].get("NewImage", {})
10        print("Processing inserted item:", json.dumps(new_item))
11
12    return {"statusCode": 200}

This works everywhere and is easy to understand.

The downside is that Lambda still gets invoked for updates and deletes, even though your code skips them.

A Better Current Option: Event Source Filtering

AWS Lambda now supports event source filtering for some event sources, including DynamoDB Streams. That means the event source mapping can reject non-insert records before they reach your handler.

Using the CLI, an event source mapping can include a filter pattern such as:

bash
1aws lambda create-event-source-mapping \
2  --function-name ProcessNewOrders \
3  --event-source-arn arn:aws:dynamodb:us-east-1:123456789012:table/Orders/stream/2025-01-01T00:00:00.000 \
4  --starting-position LATEST \
5  --filter-criteria '{"Filters":[{"Pattern":"{ \"eventName\": [\"INSERT\"] }"}]}'

With this approach, only INSERT records are delivered to the Lambda function.

That is cleaner and can reduce unnecessary invocations.

Lambda Handler Still Benefits from Defensive Checks

Even with event source filtering configured, it is still reasonable to keep the handler defensive.

python
1def lambda_handler(event, context):
2    for record in event.get("Records", []):
3        if record.get("eventName") != "INSERT":
4            continue
5
6        item = record["dynamodb"]["NewImage"]
7        # Business logic here.
8        print(item)

This protects you if the mapping changes later or if the code is reused in another environment.

IAM and Trigger Wiring

Your Lambda execution role does not need broad DynamoDB table write permissions just to consume the stream. The event source mapping handles reading from the stream service side, while the function role mostly needs whatever downstream permissions your business logic requires.

The practical setup steps are:

  1. enable DynamoDB Streams on the table
  2. choose a stream view that includes the fields you need
  3. create the Lambda function
  4. add an event source mapping
  5. optionally apply event filtering for INSERT

That is the actual insert-only pipeline.

Common Pitfalls

A common mistake is searching for a DynamoDB table option that makes the stream itself insert-only. That setting does not exist.

Another issue is enabling KEYS_ONLY and then expecting NewImage to appear in the Lambda event. Choose the stream view based on what your handler needs.

Developers also sometimes rely entirely on handler-side filtering and then wonder why the function is still invoked for updates and deletes. Event source filtering exists precisely to avoid that overhead.

Finally, if you add event filtering, test the exact filter JSON carefully. A malformed pattern can silently lead to unexpected behavior.

Summary

  • DynamoDB Streams always capture multiple event types when enabled.
  • Insert-only behavior is implemented at the consumer level, not the table level.
  • Use NEW_IMAGE if the Lambda needs the inserted item contents.
  • For cleaner behavior, use Lambda event source filtering on eventName == INSERT.
  • Keep handler code defensive even when filtering is configured upstream.

Course illustration
Course illustration

All Rights Reserved.