Architecture3 min read

EventBridge Pipes and Scheduler: Deleting the Glue Lambdas

Every serverless codebase accumulates small Lambdas whose only job is to move data from A to B or run something on a timer. EventBridge Pipes and EventBridge Scheduler replace most of them with configuration. Here's where each fits and what to watch.

Gopal Yendluri
Series: Event-Driven Architecture on AWS · Part 2 of 3
  1. Queue Everything: How SQS-Based Architecture Improved Our API Response Times
  2. EventBridge Pipes and Scheduler: Deleting the Glue Lambdas
  3. EventBridge vs SNS: When to Use Which (and When to Use Both)
Contents
  1. The Glue Lambda Problem
  2. EventBridge Pipes: Point-to-Point Integration as Configuration
  3. EventBridge Scheduler: Cron Done Properly
  4. Pipes, Scheduler, or Code?
  5. The Takeaway

The Glue Lambda Problem

Look through any mature serverless estate and you'll find functions like these:

  • A Lambda that reads a DynamoDB stream, drops irrelevant records and forwards the rest to SQS.
  • A Lambda that polls a queue, calls an internal API to enrich each message, and posts it somewhere else.
  • A "cron" Lambda triggered every five minutes that checks a table for things due to happen.
  • A Lambda that exists only to call a third-party webhook with a transformed payload.

Each one needs code, tests, deploys, IAM, logging, alarms and runtime upgrades. None of them contain business logic. Two EventBridge features exist largely to delete them.

EventBridge Pipes: Point-to-Point Integration as Configuration

A pipe connects one source to one target, with optional filtering and enrichment in between:

Source ──► Filter ──► Enrichment (optional) ──► Target
  • Sources: SQS, Kinesis Data Streams, DynamoDB Streams, Amazon MSK and self-managed Kafka, Amazon MQ.
  • Filtering: the same event-pattern syntax as EventBridge rules. Filtered-out events are dropped before you pay for enrichment or targets.
  • Enrichment: Lambda, Step Functions (Express), API Gateway, or an API destination (any HTTP endpoint).
  • Targets: a long list including SQS, SNS, Step Functions, Lambda, EventBridge buses, Kinesis, ECS tasks, API destinations and more.
  • Input transformation to reshape the payload for the target.

Example: DynamoDB Stream → only cancelled subscriptions → event bus

# Simplified CloudFormation
SubscriptionCancelledPipe:
  Type: AWS::Pipes::Pipe
  Properties:
    RoleArn: !GetAtt PipeRole.Arn
    Source: !GetAtt SubscriptionsTable.StreamArn
    SourceParameters:
      DynamoDBStreamParameters:
        StartingPosition: LATEST
        BatchSize: 10
      FilterCriteria:
        Filters:
          - Pattern: '{"eventName":["MODIFY"],"dynamodb":{"NewImage":{"status":{"S":["cancelled"]}}}}'
    Target: !GetAtt DomainEventBus.Arn
    TargetParameters:
      EventBridgeEventBusParameters:
        DetailType: SubscriptionCancelled
        Source: com.company.subscriptions
      InputTemplate: '{"subscriptionId": <$.dynamodb.NewImage.id.S>, "customerId": <$.dynamodb.NewImage.customerId.S>}'

No function code. The table's change stream becomes a clean domain event on the bus, where other teams can subscribe with rules.

Where Pipes shine

  • Change data capture to events. DynamoDB or Kinesis streams into domain events.
  • Queue-to-workflow. SQS into Step Functions, with filtering, so each message starts a workflow.
  • Enrich-then-forward. Add customer data from an internal API before delivering to a partner endpoint.

Watch out for

  • Pipes are one-to-one. For fan-out, target an event bus or SNS topic and fan out from there.
  • Error handling differs by source. Stream sources need a dead-letter configuration and a retry/bisect strategy; SQS sources rely on the queue's redrive policy. Set these explicitly.
  • Enrichment is synchronous. A slow enrichment endpoint throttles the whole pipe.

EventBridge Scheduler: Cron Done Properly

EventBridge Scheduler is a separate service from the older "scheduled rules" on an event bus, and it's much more capable:

  • One-time and recurring schedules (cron, rate, or a specific timestamp).
  • Time zones and daylight saving handled correctly, which matters when your cut-off is "10pm UK time" all year round.
  • Massive scale. Designed for very large numbers of schedules, so you can create one schedule per entity rather than one schedule that scans a table.
  • Universal targets. Call almost any AWS API directly, not just Lambda.
  • Flexible time windows to spread load, plus retry policies and dead-letter queues.

Example: per-customer reminder instead of a polling job

The old pattern: a Lambda runs every five minutes, queries for "customers whose delivery cut-off is in 24 hours", and sends reminders. It's wasteful, and easy to get wrong around daylight saving changes.

The Scheduler pattern: when a delivery is scheduled, create a one-time schedule for exactly 24 hours before the cut-off.

import { SchedulerClient, CreateScheduleCommand } from "@aws-sdk/client-scheduler";
 
const scheduler = new SchedulerClient({});
 
await scheduler.send(new CreateScheduleCommand({
  Name: `cutoff-reminder-${deliveryId}`,
  GroupName: "delivery-reminders",
  ScheduleExpression: `at(${reminderTime})`,   // e.g. at(2026-02-20T22:00:00)
  ScheduleExpressionTimezone: "Europe/London",
  FlexibleTimeWindow: { Mode: "OFF" },
  ActionAfterCompletion: "DELETE",
  Target: {
    Arn: remindersQueueArn,
    RoleArn: schedulerRoleArn,
    Input: JSON.stringify({ deliveryId, customerId }),
    DeadLetterConfig: { Arn: schedulerDlqArn },
  },
}));

When the delivery is skipped or rescheduled, delete or update the schedule. No polling, no table scans, and the DST edge case is AWS's problem.

Watch out for

  • Keep schedules in sync with your source of truth. If an update to the delivery fails to update the schedule, you'll send a wrong reminder. Make schedule changes part of the same idempotent workflow.
  • Name schedules deterministically (like cutoff-reminder-{deliveryId}) so updates and deletes are simple and retries are idempotent.
  • Target a queue, not the worker. Delivering to SQS keeps retries and concurrency under your control.

Pipes, Scheduler, or Code?

Need Use
Move data from one stream or queue to one target, with filtering Pipes
Enrich messages with an API call before delivery Pipes with enrichment
Fan out one event to many consumers Event bus rules (or SNS)
Run something at a specific time per entity Scheduler (one-time schedules)
Run a platform job on a recurring cadence Scheduler (recurring)
Real business logic, complex branching Code (Lambda) or Step Functions

The Takeaway

Code that contains no business logic is a liability. Before writing the next glue Lambda, check whether a pipe or a schedule expresses it as configuration. You'll delete code, remove runtime upgrades from your backlog, and make the integration visible in infrastructure definitions rather than buried in a handler.

Next in Event-Driven Architecture on AWS
EventBridge vs SNS: When to Use Which (and When to Use Both)
EventBridgeEventBridge PipesEventBridge SchedulerAWSserverlessSQS