EventBridge Pipes make it incredibly simple to move data between AWS services with minimal glue code. One of the most powerful—but often overlooked—features of Pipes is the ability to reshape or filter event payloads using InputTransformers, particularly InputTemplate.

In this post, we’ll walk through how to use InputTemplate in a Pipe Target configuration to convert a raw DynamoDB Stream event into a clean, application-friendly EventBridge event. We’ll also explore the limitations of this approach and when to introduce an enrichment Lambda for more advanced logic.


Why InputTemplate?

When you connect a DynamoDB Stream directly to an EventBridge bus using a Pipe, the raw stream event contains a large amount of metadata:

  • eventName, eventVersion
  • AWS region and account info
  • StreamViewType
  • NewImage / OldImage values
  • DynamoDB type wrapper (S, N, BOOL, etc.)

Most consumers don’t want the entire DynamoDB Stream event. Instead, they need:

✔ Only the fields that matter ✔ In a format suited to the consumer ✔ In a domain-driven structure (not DynamoDB JSON shapes)

This is exactly what InputTemplate is designed for.


Transforming DynamoDB Stream Events with InputTemplate

Below is the Pipe CloudFormation resource that performs the transformation:

AuditLogPipe:
  Type: AWS::Pipes::Pipe
  Properties:
    Name: DynamoDBStreamToEventBridgePipe
    RoleArn: !GetAtt PipeExecutionRole.Arn
    LogConfiguration:
      CloudwatchLogsLogDestination:
        LogGroupArn: !GetAtt AuditLogPipeLogGroup.Arn
      Level: TRACE
      IncludeExecutionData:
        - ALL

    # SOURCE — DynamoDB Stream ARN
    Source: !GetAtt AuditLogsTable.StreamArn
    SourceParameters:
      DynamoDBStreamParameters:
        BatchSize: 1
        StartingPosition: LATEST
    
    # TARGET — EventBridge Bus
    Target: !GetAtt CustomEventBus.Arn
    TargetParameters:
      InputTemplate: |
        {
          "eventId": "<$.dynamodb.NewImage.eventId.S>",
          "entity": {
            "id": "<$.dynamodb.NewImage.entityId.S>",
            "type": "<$.dynamodb.NewImage.entityType.S>"
          },
          "metadata": {
            "timestamp": "<$.dynamodb.NewImage.timestamp.S>"
          } 
        }        
      EventBridgeEventBusParameters:
        DetailType: "AuditLogsTableStream"
        Source: "${self:service}"

✔ How this works

  • InputTemplate shapes the outgoing event exactly as you want it.
  • The <$> paths reference fields inside the DynamoDB Stream structure.
  • Only the NewImage contents are mapped.
  • The result is a clean detail object on the EventBridge bus.

What the final EventBridge event looks like

EventBridge wraps the output of your InputTemplate inside the EventBridge envelope:

{
  "version": "0",
  "id": "37cc0791-56bf-b010-ac59-943215863f56",
  "detail-type": "AuditLogsTableStream",
  "source": "stepfunctions-example",
  "account": "741829461075",
  "time": "2025-11-29T11:05:35Z",
  "region": "eu-west-2",
  "resources": [],
  "detail": {
    "eventId": "01JDPXM8K2YFQN7VWZH3RTGB5L",
    "entity": {
      "id": "01JDQ7YGN4X8KPWM2VQZS6THRC",
      "type": "Stock"
    },
    "metadata": {
      "timestamp": "2025-11-28T13:16:19.848Z"
    }
  }
}

This is far cleaner and easier for downstream consumers to process.


🚧 Limitation: EventBridgeEventBusParameters Cannot Be Dynamic

The biggest gap in this pattern is that EventBridgeEventBusParameters cannot reference values from the incoming DynamoDB event.

You cannot dynamically set:

  • DetailType
  • Source
  • EventBus ARN
  • Resources list

For example, you cannot do:

DetailType: "<$.dynamodb.NewImage.eventType.S>"

EventBridge will not evaluate the InputTemplate inside the envelope fields.

This means that although your event detail can be fully dynamic, the event metadata cannot be.


🔧 Solution: Add a Lambda Enricher

Fortunately, EventBridge Pipes support an Enrichment Step, which allows transforming or augmenting events using a Lambda function before they reach the target.

In this model:

DynamoDB Stream → Pipe → Enricher Lambda → EventBridge Bus

The Lambda can:

  • compute a dynamic detail-type
  • compute a dynamic source
  • strip DynamoDB JSON types
  • apply business logic rules
  • add new fields
  • route to different buses or event patterns

Example use cases

  • detail-type equals NewImage.eventType
  • Route events from a single table into different domains
  • Flatten the DynamoDB JSON ({ "S": "..." }) into plain JSON

With an enricher Lambda, you are no longer limited by EventBridge Pipe’s static metadata fields.


When to use InputTemplate vs Enricher Lambda

Need Use InputTemplate Use Enricher Lambda
Extract only NewImage
Reshape JSON
Remove DynamoDB types (S, N) ⚠ Partial
Add static DetailType / Source
Set dynamic DetailType / Source
Conditional logic
Add computed fields

Final Thoughts

EventBridge Pipes + InputTemplate give you a clean, low-code way to push DynamoDB Stream events into EventBridge in a domain-friendly shape. For many use cases—especially simple auditing or change-notification flows—this is more than enough.

However, when you need dynamic metadata, business logic, or more advanced transformation, adding a Lambda enricher unlocks the full flexibility of custom event formatting.

Pipes give you the best of both worlds: low code when possible, full control when necessary.