Course outline

19.5

Amazon EventBridge

Event buses, rules and patterns, schedules, schema registry, cross-account buses, archive and replay, and Pipes.

24 min Reading + animations

Tip: tap or hover any dotted-underlined term to see what it means.

By the end of this lesson you will be able to

  • Explain what Amazon EventBridge is (formerly CloudWatch Events): a serverless event bus that receives events from AWS services, your own applications and SaaS partners, and routes them by rules to targets.
  • Read an event (source, detail-type, detail, account, region, time) and tell the default, custom and partner event buses apart.
  • Write event patterns with exact, prefix, suffix, anything-but, numeric, exists and equals-ignore-case matching, and choose targets, input transformation, a retry policy and a dead-letter queue.
  • Give targets the right permission: a resource-based policy (Lambda, SNS, SQS, API Gateway, CloudWatch Logs) or an IAM role (Kinesis, Step Functions, ECS, Systems Manager…).
  • Run things on a clock with EventBridge Scheduler (time zones, one-time schedules) instead of legacy scheduled rules, and call any HTTPS API with API destinations.
  • Share events across accounts and Regions with bus policies, keep and replay events with archives, describe events with the schema registry, and connect a source to a target with EventBridge Pipes.
  • Pick EventBridge, SNS or SQS from a scenario’s words.

#Why EventBridge: react when something happens

The last four lessons were about watching: metrics, logs, alarms and Insights tell you how things are doing. This lesson is about reacting: when something happens somewhere in your account, in your application or at a partner, something else should start, without anyone writing glue code that polls for it.

#The problem

A ride-sharing app in Dhaka, Pathao-style, finishes thousands of rides an hour. Each finished ride must reach billing, the driver-payout workflow, the loyalty-points service, and, from next month, a fraud model. If the trip service calls each of them directly, it must know all of them, wait for all of them, and change its code every time a team is added. If one of them is down, the trip service fails too.

Meanwhile the operations team wants an email when a production EC2 instance stops, the security team wants a Lambda function to run when someone opens port 22, and the wallet team wants refund notifications from its payment gateway. Writing a poller for each of these is slow, costly and fragile.

#What EventBridge is

Amazon EventBridge (formerly CloudWatch Events, still visible in some IAM action names and older documentation) is a serverless event bus:

  • An event is a small JSON document that says something happened: an instance stopped, an object was uploaded, a ride was completed.
  • An event bus receives events. Producers put events on a bus and move on; they do not know who listens.
  • A rule on the bus has an event pattern. Every event is compared with every rule; a matching event goes to the rule’s targets (up to five), such as a Lambda function, an SQS queue, an SNS topic or a Step Functions state machine.
  • There are no servers to run and nothing to scale. You pay per event published (AWS service events on the default bus are free) and per feature used.

This is event-driven architecture: producers and consumers are decoupled, and a new consumer is a new rule, not a change to the producer.

#Events: what one looks like

Every event on a bus has the same envelope. This is the event EC2 sends when an instance stops:

{
  "version": "0",
  "id": "7bf73129-1428-4cd3-a780-95db273d1602",
  "detail-type": "EC2 Instance State-change Notification",
  "source": "aws.ec2",
  "account": "111122223333",
  "time": "2026-11-01T06:30:00Z",
  "region": "ap-southeast-1",
  "resources": ["arn:aws:ec2:ap-southeast-1:111122223333:instance/i-0abcd1234example"],
  "detail": { "instance-id": "i-0abcd1234example", "state": "stopped" }
}
FieldMeaning
sourceWho produced it. AWS services use aws.<service> (aws.ec2, aws.s3); your own apps choose a name such as ride.app (names starting with aws. are reserved).
detail-typeWhat kind of event, together with source the main thing rules match on.
detailThe event’s own data, any JSON the producer decides.
account, regionWhere it happened. Useful in patterns when events arrive from several accounts.
timeWhen it happened (UTC).
id, resources, versionA unique ID, the ARNs involved, the envelope version.

An event can be up to 1 MB since January 2026 (before that the limit was 256 KB, the number many exam questions and courses still use). Custom events are billed in 64 KB chunks.

#Where events come from

  • AWS services put events on the default bus by themselves: EC2 state changes, Auto Scaling actions, ECS task state changes, CodeBuild and CodePipeline results, GuardDuty and Security Hub findings, AWS Health events, Trusted Advisor checks, scheduled-change notices and many more.
  • Any API call recorded by CloudTrail arrives as an AWS API Call via CloudTrail event, so even services without their own events can trigger rules (examples in lesson 19.6).
  • Amazon S3 sends its events directly to EventBridge once you turn on Send notifications to Amazon EventBridge on the bucket (lesson 10.7).
  • Your applications call PutEvents (SDK, CLI) on a bus.
  • SaaS partners send events to a partner event source in your account.
  • Schedules start targets at given times (section below).

#Event buses: default, custom and partner

An event bus is the channel that receives events and runs rules on them. Buses are regional, and there are three kinds:

BusReceivesExample
Default event busEvents from AWS services in this account and Region (created for you, cannot be deleted). Your apps can also put events on it.An EC2 instance stops; root signs in; a CloudTrail API call.
Custom event busEvents from your own applications and microservices. You create as many as you need (100 per account per Region by default).The ride app’s rides bus with Ride Completed and Ride Cancelled events.
Partner event busEvents from a SaaS partner (Datadog, Auth0, Zendesk, Shopify, Salesforce, …). The partner creates a partner event source in your account; you associate it with a partner bus.A payment gateway’s refund events reaching the wallet team’s account.

A custom bus keeps an application’s events apart from AWS’s own events: its own rules, its own resource policy, its own archive. The default bus is the right place for reactions to AWS events.

Three buses, one idea: an event comes in, a rule matches, targets run

An AWS service event on the default bus, a ride app’s own event on a custom bus, and a payment gateway’s event on a partner bus. Watch which events a rule picks up and which ones simply disappear.

Scenario

An EC2 instance stops; nobody wrote code, yet a Lambda function and an email react.

EC2 instancestate: stopped
Default busdefault
Ruleevent pattern
Lambda function
SNS topic
event

The event (JSON)

source

aws.ec2

detail-type

EC2 Instance State-change Notification

account

111122223333

region

ap-southeast-1

detail.state

stopped

Step 1 of 4
1

A production EC2 instance stops. EC2 itself publishes a state-change event to the default bus of this account and Region. Nothing had to be switched on: every account has a default bus, and AWS services write to it on their own.

#Rules and event patterns

A rule belongs to one bus and has either an event pattern (react to matching events) or a schedule (legacy, see below), plus up to five targets. A bus can have 300 rules by default (adjustable). Every rule sees every event on its bus, so one event can trigger many rules.

An event pattern is JSON with the same shape as the events it matches:

{
  "source": ["aws.ec2"],
  "detail-type": ["EC2 Instance State-change Notification"],
  "detail": { "state": ["stopped", "terminated"] }
}

The matching rules are simple and strict:

  • Every field named in the pattern must match (AND). Fields the pattern does not name are ignored.
  • The value of a field is a list; any item may match (OR).
  • Matching is exact and case-sensitive unless you use an operator.
  • If the event’s field is a list, the pattern matches when any element matches.
  • A field the event does not have fails the match (except exists: false).

The operators go inside the list:

OperatorExampleMatches
exact value"state": ["stopped"]exactly that string or number
prefix"key": [{ "prefix": "invoices/" }]strings starting with it
suffix"key": [{ "suffix": ".pdf" }]strings ending with it
anything-but"city": [{ "anything-but": ["Dhaka"] }]any value except those (the field must exist)
numeric"fare": [{ "numeric": [">", 0, "<=", 5000] }]numbers in a range
exists"promo-code": [{ "exists": true }]the field is present (or absent with false)
equals-ignore-case"detail-type": [{ "equals-ignore-case": "ride completed" }]the string in any letter case
cidr"sourceIPAddress": [{ "cidr": "198.51.100.0/24" }]IP addresses in a range
wildcard"key": [{ "wildcard": "invoices/*/2026/*.pdf" }]* anywhere (at most 30 such rules per bus)
$or"$or": [{ "fare": [{ "numeric": [">", 5000] }] }, { "city": ["Sylhet"] }]either set of fields

Event-pattern tester

Pick an event and a rule’s event pattern, then test. You will see whether the rule would fire, and which field stopped it if not.

Sample event

Event pattern

{  "version": "0",  "id": "7bf73129-1428-4cd3-a780-95db273d1602",  "detail-type": "EC2 Instance State-change Notification",  "source": "aws.ec2",  "account": "111122223333",  "time": "2026-11-01T06:30:00Z",  "region": "ap-southeast-1",  "resources": [    "arn:aws:ec2:ap-southeast-1:111122223333:instance/i-0abcd1234example"  ],  "detail": {    "instance-id": "i-0abcd1234example",    "state": "stopped"  }}
{
  "source": [
    "aws.ec2"
  ],
  "detail-type": [
    "EC2 Instance State-change Notification"
  ],
  "detail": {
    "state": [
      "stopped",
      "terminated"
    ]
  }
}

Press “Test the pattern” to evaluate it, as EventBridge does for every event on the bus.

#Targets

When an event matches, the rule sends it to each of its targets (in parallel, up to five per rule). Common targets:

  • Compute: Lambda function, ECS task (Fargate or EC2), AWS Batch job queue, Step Functions state machine, Systems Manager Run Command or Automation, SageMaker pipeline.
  • Messaging and integration: SQS queue (standard, FIFO with a message group), SNS topic, Kinesis Data Streams, Amazon Data Firehose (for example into S3), another event bus, an API destination, API Gateway, AppSync.
  • Operations: CloudWatch log group, Incident Manager response plan, CodeBuild, CodePipeline, and EC2 actions (create an EBS snapshot, reboot, stop, terminate an instance).

Need more than five targets for one event? Use several rules with the same pattern, or one target that fans out (an SNS topic, or another bus).

#Shaping what the target receives

By default the target gets the whole event. Per target you can send instead:

  • part of the event, by a JSON path such as $.detail;
  • a constant JSON text;
  • an input transformer: pick values with paths, then place them in a template.
{
  "InputPathsMap": { "ride": "$.detail.ride-id", "fare": "$.detail.fare" },
  "InputTemplate": "{\"text\": \"Ride <ride> earned <fare> taka\"}"
}

The transformer is how you match an API’s expected body, give a Lambda function a small clean input, or write a readable SNS email.

#Retries and the dead-letter queue

If a target cannot be reached (throttled, down, network trouble), EventBridge retries with exponential back-off and jitter. Each target has a retry policy:

  • Maximum age of event: 60 seconds to 24 hours (default 24 hours).
  • Retry attempts: 0 to 185 (default 185).

When the retries run out, the event is dropped, unless the target has a dead-letter queue (DLQ): a standard SQS queue (not FIFO) in the same Region as the rule. The DLQ message carries attributes such as RULE_ARN, TARGET_ARN, ERROR_CODE and EXHAUSTED_RETRY_CONDITION, so you can fix the cause and re-send.

Some errors are not retried at all, because retrying cannot help: a missing permission, a target that no longer exists, an invalid address. Those events go straight to the DLQ (or are dropped). Delivery is at least once, so targets must be idempotent.

Two different silences to keep apart: an event that matches no rule is never delivered and never reaches a DLQ (watch the MatchedEvents metric); an event that matched but failed is retried and then dropped or sent to the DLQ (watch FailedInvocations, and alarm on it, lesson 19.3).

#Permissions for targets

When a rule runs, EventBridge calls the target, so EventBridge needs permission on that target. There are two ways:

PermissionTargetsHow
Resource-based policy on the targetLambda, SNS, SQS, API Gateway, CloudWatch LogsThe target’s policy allows the service principal events.amazonaws.com, ideally only for this rule’s ARN (aws:SourceArn). The console adds it for you; with the CLI or IaC you add it yourself (aws lambda add-permission).
IAM role that EventBridge assumesKinesis Data Streams, Firehose, Step Functions, ECS tasks, Batch, Systems Manager Run Command and Automation, CodeBuild, EC2 actions, event buses in another account…The rule’s target has a role ARN; the role trusts events.amazonaws.com and allows the action (states:StartExecution, kinesis:PutRecord…).

Since 2025 an execution role can also be used for Lambda, SNS and SQS targets (CloudWatch Logs targets still use a resource policy), but the classic split above is what the exam asks. If the target is encrypted with a customer managed KMS key (for example an SQS queue with SSE-KMS), the key policy must also let EventBridge use the key.

When a target fails: retries, a dead-letter queue, or silence

A Ride Completed event matches the payout rule, but the payout Lambda function cannot take it. What EventBridge does next depends on the error and on the target’s retry policy and DLQ.

Scenario

A temporary error is retried with back-off until the target can take the event.

Custom busrides
Payout rule
Payout Lambda
Target DLQstandard queue
match
Step 1 of 4
1

Eid evening, thousands of rides end at once. The event matches the payout rule, which has the Lambda function as its target.

#Schedules: scheduled rules and EventBridge Scheduler

EventBridge has always been able to start targets on a timetable, replacing a server that runs cron:

  • A scheduled rule (legacy) has a rate() expression (rate(4 hours)) or a cron() expression with six fields (cron(0 20 * * ? *) = every day at 20:00), lives only on the default bus, always runs in UTC, has one-minute precision, and up to five targets.
  • Amazon EventBridge Scheduler (2022) is a separate, purpose-built scheduler and is what AWS now recommends. It adds time zones (with daylight saving handled), one-time schedules (at(2026-11-11T00:00:00)), schedules that delete themselves after running, start and end dates, flexible time windows that spread invocations over a few minutes, a retry policy and DLQ per schedule, millions of schedules per account, and targets in more than 270 services through universal targets (any API action), not only the classic target list. The first 14 million invocations a month are free, then 1 USD per million.
Scheduled rule (legacy)EventBridge Scheduler
Time zoneUTC onlyAny time zone, daylight saving handled
One-time runNoYes, at(), can delete itself
ScaleCounts against 300 rules per busMillions of schedules
TargetsUp to 5, classic target list1 per schedule, templated or any of 6,000+ API actions
WhereDefault busIts own service and API (aws scheduler)

Running things on a clock: Scheduler and scheduled rules

A news portal builds a readership report every night at 02:00 Dhaka time, and an online shop starts its 11.11 sale at midnight. Compare EventBridge Scheduler with the older scheduled rule.

Scenario

Scheduler runs a cron expression in the time zone you choose.

EventBridge Schedulerschedule02:00 Asia/Dhaka
Lambda function
Report bucket
Step 1 of 3
1

The schedule: cron(0 2 * * ? *) with time zone Asia/Dhaka. Scheduler understands time zones and daylight saving, so 02:00 means 02:00 local time all year.

#API destinations: call any HTTPS endpoint

An API destination is a target that is an HTTPS endpoint anywhere: a SaaS API (Salesforce, Slack, a courier company’s booking API), or your own service. It is made of:

  • a connection, which holds the authorization: Basic (user name and password), OAuth client credentials (EventBridge fetches and refreshes the token) or an API key header. The secret is stored for you in AWS Secrets Manager (lesson 21.3);
  • the endpoint URL and HTTP method;
  • an invocation rate limit per second (300 by default, adjustable), so a burst of events does not overload the partner: extra invocations are delayed, not lost (within the retry policy).

Use an input transformer to shape the body the API expects. Retries and a DLQ work as for other targets. Since late 2024 a connection can also reach private endpoints inside a VPC or on premises (through VPC Lattice resource configurations), with a small quota per account.

#Schema registry and schema discovery

A schema describes the structure of an event: which fields detail has and their types (OpenAPI 3 or JSON Schema Draft 4).

  • The schema registry stores schemas in one place, so a developer can see what an event contains before writing code. AWS events already have schemas in the aws.events registry; you create your own registries for your events. Schemas are versioned.
  • Schema discovery, turned on for a bus, looks at the events passing through and infers their schemas automatically, adding a new version when the structure changes.
  • Code bindings: from a schema, EventBridge generates strongly-typed classes for Java, Python, TypeScript and Go, so application code works with RideCompleted.getFare() instead of digging through raw JSON.

The registry is free; discovery is billed per ingested event after 5 million free a month.

#Across accounts and Regions

#Resource-based policy on the bus

A bus is protected by a resource-based policy, alongside the IAM (identity-based) policies of the people and roles that call it. The bus policy decides who from outside may put events on it (and who may manage its rules):

  • Allow one account: "Principal": {"AWS": "arn:aws:iam::111122223333:root"}, action events:PutEvents.
  • Allow a whole AWS Organization: principal * with the condition aws:PrincipalOrgID (Organizations is lesson 20.1).

The sender creates a rule whose target is the other account’s bus ARN, with an IAM role EventBridge assumes (required for every new cross-account bus target since March 2023, so organization SCPs apply). The receiver creates rules on its bus, ideally with the account field in the pattern so that only expected senders trigger them. Events crossing accounts are billed to the sender as custom events.

A typical design is the slides’ central event bus: every account of the organization forwards selected events (security-group changes, GuardDuty findings, root sign-ins) to one bus in a security or operations account, where one set of rules acts on all of them.

Two limits to remember: one hop only (a bus that received an event from another account cannot forward it on to a third account), and direct cross-account targets (since January 2025) let a rule deliver straight to an SQS queue, Lambda function, SNS topic, Kinesis stream or API Gateway in another account, if that resource’s policy allows it, without a bus in the middle.

#Cross-Region

A rule can target an event bus in another Region (same or different account). Use it to collect events from all Regions in one, or to keep a copy for disaster recovery. Remember that the default bus is regional: a rule in ap-southeast-1 never sees events from eu-west-1, and events from global services such as IAM sign-in appear in us-east-1 (lesson 19.6).

Sending events to another account: blocked until the bus allows it

A telecom’s security team collects security-group changes from every workload account into one central bus. The receiving bus decides who may send.

Scenario

The sender has a rule, but the receiving bus never allowed the account.

Workload account111122223333
Security account444455556666
CloudTrailAPI call
Default busrule → central
Central busorg-events
Alert Lambda
API call event
Step 1 of 3
1

At 12:00 someone opens port 22 to the world in a workload account. CloudTrail records the security-group API call, and EventBridge puts an AWS API Call via CloudTrail event on the default bus (lesson 19.6).

#Archive and replay

  • An archive stores events sent to a bus: all of them or only those matching an event pattern, kept for a number of days or indefinitely. It starts empty and only holds events that arrive after it is created.
  • A replay re-sends archived events from a chosen time window back to the same bus the archive belongs to, either to all rules or only to the rules you pick. Replayed events carry a replay-name field. They are not guaranteed to come in the original order.

Uses: reprocess after a bug fix, recover after a target was down for longer than the retry policy, test a new consumer with real past traffic, or rebuild a read model. Make consumers idempotent: a replay delivers events they may have handled once already.

Cost: archive processing per GB and storage per GB-month; replayed events are billed like custom events.

Archive the events, fix the bug, replay the morning

The ride app’s bus keeps a copy of every Ride Completed event. When a fare bug is found, the team replays two hours of events through the fixed code.

Scenario

An archive on the bus stores all events, or only those matching its pattern, for a set time or for ever.

Ride app
Custom busrides
Fare Lambdarule target
Archiverides-archive
Step 1 of 3
1

The team creates an archive on the rides bus with an event pattern (only Ride Completed) and a retention of 365 days. Retention can also be indefinite. Without a pattern, the archive keeps every event on the bus.

#EventBridge Pipes

A bus is for many-to-many routing. Often you just need to move data from one source to one target, maybe filtered and enriched. Before Pipes that meant writing a Lambda function that polls a queue or stream, filters, calls another service and forwards. EventBridge Pipes does it without code:

  1. Source: an SQS queue, Kinesis Data Streams, DynamoDB Streams, Amazon MSK, self-managed Apache Kafka, or Amazon MQ. The pipe polls it for you, in batches.
  2. Filter (optional): an event pattern, the same language as rules. Events that do not match are dropped and not billed.
  3. Enrichment (optional): call a Lambda function, a Step Functions Express workflow, an API Gateway API or an API destination, and use its answer as the new event.
  4. Target: one of many, including Step Functions, an event bus, Kinesis, Firehose, SQS, SNS, Lambda, ECS tasks, API destinations, Redshift and more. An input transformer can reshape the data.

Errors follow the source: an SQS message that fails goes back to the queue and, after its maxReceiveCount, to the queue’s own DLQ; stream sources have retry settings and a DLQ on the pipe. Pipes cost 0.40 USD per million requests after filtering.

EventBridge Pipes: source → filter → enrichment → target

An online shop’s new orders land in an SQS queue. A pipe takes only paid orders, adds the customer’s address, and starts the delivery workflow, with no polling code.

Scenario

The pipe polls the queue, filters, enriches and starts the target.

Pipe: orders-to-delivery
SQS queuesource
Filterevent pattern
EnrichmentLambda
Step Functionstarget
order paid
Step 1 of 4
1

The pipe reads the queue itself: no Lambda poller or worker server to write. Sources can be SQS, Kinesis Data Streams, DynamoDB Streams, Amazon MSK, self-managed Kafka or Amazon MQ.

#EventBridge, SNS or SQS?

All three decouple producers from consumers, which is why scenario questions mix them up. Lesson 13.7 compares the messaging services in depth; the short version:

EventBridgeSNSSQS
ModelEvent bus, content-based rulesTopic, push to all subscribers (pub/sub)Queue, consumers pull
FilteringRich patterns on any field of the eventSubscription filter policies on attributes or bodyNone (consumers get every message)
SourcesAWS services, CloudTrail API calls, SaaS partners, your apps, schedulesYour apps and some AWS servicesYour apps
ConsumersUp to 5 targets per rule, many rules, 20+ target types, API destinationsVery many subscribers (Lambda, SQS, HTTPS, email, SMS)One consumer per message
StorageNone, except an archiveNoneMessages kept until deleted (up to 14 days)
Typical latency and scaleAbout half a second, high but quota-limited throughputVery high throughput, low latencyBuffers any backlog

Rules of thumb: AWS service events, SaaS events, cross-account routing and schedules → EventBridge. Massive fan-out to many subscribers, SMS or email to people → SNS. Buffering work for workers, absorbing spikes → SQS (often as an EventBridge or SNS target).

#What goes wrong

  • The rule never fires. The pattern does not match: a typo in detail-type, a case difference, a number written as a string ("420" does not match a numeric condition), a field nested at the wrong level, or the rule is on the wrong bus or in the wrong Region. Test with aws events test-event-pattern and watch MatchedEvents.
  • Root sign-in or IAM rules never fire in your Region. IAM and other global-service events are delivered in us-east-1, and root console sign-ins in us-east-1, us-east-2 or us-west-2; create the rule there (lesson 19.6).
  • A Lambda target is never invoked after deploying with the CLI or IaC: no resource-based permission for events.amazonaws.com. The event goes to the DLQ with NO_PERMISSIONS, or is dropped.
  • Events disappear after an outage longer than the retry policy, with no DLQ configured. Add a DLQ to every important target and alarm on FailedInvocations.
  • Duplicates after retries or replays: delivery is at least once. Use an idempotency key (ride ID, order ID).
  • Cross-account events never arrive: no bus policy on the receiver, no IAM role on the sender’s target, or a second hop to a third account.
  • An infinite loop: a Lambda function triggered by an S3 or DynamoDB change writes the same kind of change, which triggers it again. Narrow the pattern (a prefix, a field the function does not set) and set alerts on invocation counts.
  • The scheduled job runs at the wrong hour: a legacy scheduled rule in UTC. Use Scheduler with a time zone.
  • Throttling: PutEvents and target invocations have per-Region quotas (thousands per second, adjustable). Batch PutEvents calls and request increases before a sale or an Eid rush.
  • A replay finds nothing: the archive was created after the events happened.
  • A SaaS integration delivers nothing: the partner event source was never associated with a partner bus.

#EventBridge in system design

  • Event-driven microservices: each service publishes domain events (Order Placed, Ride Completed) to a custom bus; other services subscribe with rules. Adding a consumer never touches the producer. Put an SQS queue in front of slow consumers to absorb bursts.
  • Operations automation: EC2, ECS, Auto Scaling and AWS Health events trigger Lambda functions, Systems Manager Automation runbooks or tickets; CloudWatch alarm state changes are events too.
  • Security automation: CloudTrail API calls (root sign-in, DeleteTrail, security-group changes), GuardDuty and Security Hub findings, Config compliance changes → a rule → Lambda to isolate, SNS to alert (lesson 19.6, lesson 21.7).
  • S3 processing fan-out: one bucket, many independent workflows with rich filters (size, key, metadata), including Step Functions and FIFO queues (lesson 10.7).
  • SaaS integration in both directions: partner buses in, API destinations out.
  • A central event bus per organization for security and audit events, with policies using aws:PrincipalOrgID.
  • Serverless cron: EventBridge Scheduler starting Lambda functions, ECS tasks (lesson 14.3) or Step Functions workflows; no instance just to run crontab.

When it is the wrong tool: you need a durable work queue with long retention and one consumer per message (SQS), ordered, replayable streams with many readers and high throughput (Kinesis Data Streams or MSK), or notifications to people by SMS and email at scale (SNS).

#Try it yourself

These commands use the AWS CLI v2 in ap-southeast-1. Custom events cost 1 USD per million; delete everything at the end.

# 1. A custom bus and a rule with an event pattern
aws events create-event-bus --name rides
aws events put-rule --name ride-completed --event-bus-name rides \
  --event-pattern '{"source":["ride.app"],"detail-type":["Ride Completed"],"detail":{"fare":[{"numeric":[">",0]}]}}'
# { "RuleArn": "arn:aws:events:ap-southeast-1:111122223333:rule/rides/ride-completed" }

# 2. Test the pattern against a sample event before trusting it
aws events test-event-pattern \
  --event-pattern '{"source":["ride.app"],"detail":{"city":[{"anything-but":["Dhaka"]}]}}' \
  --event '{"id":"1","account":"111122223333","source":"ride.app","time":"2026-11-01T06:32:40Z","region":"ap-southeast-1","resources":[],"detail-type":"Ride Completed","detail":{"fare":420,"city":"Chattogram"}}'
# { "Result": true }

# 3. Let EventBridge invoke the function (resource-based policy), then add it as a target
#    with a retry policy and a DLQ (a standard SQS queue whose policy allows events.amazonaws.com)
aws lambda add-permission --function-name payout --statement-id eb-ride-completed \
  --action lambda:InvokeFunction --principal events.amazonaws.com \
  --source-arn arn:aws:events:ap-southeast-1:111122223333:rule/rides/ride-completed
aws events put-targets --rule ride-completed --event-bus-name rides --targets '[{
  "Id": "payout",
  "Arn": "arn:aws:lambda:ap-southeast-1:111122223333:function:payout",
  "RetryPolicy": { "MaximumRetryAttempts": 10, "MaximumEventAgeInSeconds": 3600 },
  "DeadLetterConfig": { "Arn": "arn:aws:sqs:ap-southeast-1:111122223333:payout-dlq" },
  "InputTransformer": {
    "InputPathsMap": { "ride": "$.detail.ride-id", "fare": "$.detail.fare" },
    "InputTemplate": "{\"ride\": <ride>, \"fare\": <fare>}" } }]'
# { "FailedEntryCount": 0, "FailedEntries": [] }

# 4. Publish an event
aws events put-events --entries '[{"EventBusName":"rides","Source":"ride.app","DetailType":"Ride Completed","Detail":"{\"ride-id\":\"r-88412\",\"fare\":420,\"city\":\"Chattogram\"}"}]'
# { "FailedEntryCount": 0, "Entries": [ { "EventId": "b1e0c4a2-6f3d-4c1e-9a77-2f0d5e8c9a10" } ] }

# 5. Archive Ride Completed events for a year, and replay a time window later
aws events create-archive --archive-name rides-archive \
  --event-source-arn arn:aws:events:ap-southeast-1:111122223333:event-bus/rides \
  --event-pattern '{"detail-type":["Ride Completed"]}' --retention-days 365
aws events start-replay --replay-name fare-fix-1101 \
  --event-source-arn arn:aws:events:ap-southeast-1:111122223333:archive/rides-archive \
  --event-start-time 2026-11-01T03:00:00Z --event-end-time 2026-11-01T05:00:00Z \
  --destination '{"Arn":"arn:aws:events:ap-southeast-1:111122223333:event-bus/rides","FilterArns":["arn:aws:events:ap-southeast-1:111122223333:rule/rides/ride-completed"]}'
# { "ReplayArn": "...:replay/fare-fix-1101", "State": "STARTING" }

# 6. Allow every account of the organization to put events on the bus
aws events put-permission --event-bus-name rides --action events:PutEvents \
  --principal '*' --statement-id whole-org \
  --condition '{"Type":"StringEquals","Key":"aws:PrincipalOrgID","Value":"o-a1b2c3d4e5"}'

# 7. A nightly job at 02:00 Dhaka time with EventBridge Scheduler
aws scheduler create-schedule --name nightly-report \
  --schedule-expression 'cron(0 2 * * ? *)' --schedule-expression-timezone 'Asia/Dhaka' \
  --flexible-time-window '{"Mode":"OFF"}' \
  --target '{"Arn":"arn:aws:lambda:ap-southeast-1:111122223333:function:report","RoleArn":"arn:aws:iam::111122223333:role/scheduler-invoke-report"}'
# { "ScheduleArn": "arn:aws:scheduler:ap-southeast-1:111122223333:schedule/default/nightly-report" }

# 8. A pipe: SQS → filter → Lambda enrichment → Step Functions
aws pipes create-pipe --name orders-to-delivery \
  --role-arn arn:aws:iam::111122223333:role/pipe-orders \
  --source arn:aws:sqs:ap-southeast-1:111122223333:orders \
  --source-parameters '{"FilterCriteria":{"Filters":[{"Pattern":"{\"body\":{\"status\":[\"paid\"]}}"}]}}' \
  --enrichment arn:aws:lambda:ap-southeast-1:111122223333:function:add-address \
  --target arn:aws:states:ap-southeast-1:111122223333:stateMachine:delivery
# { "Name": "orders-to-delivery", "CurrentState": "CREATING", "DesiredState": "RUNNING" }

# 9. Clean up
aws pipes delete-pipe --name orders-to-delivery
aws scheduler delete-schedule --name nightly-report
aws events delete-archive --archive-name rides-archive
aws events remove-targets --rule ride-completed --event-bus-name rides --ids payout
aws events delete-rule --name ride-completed --event-bus-name rides
aws events delete-event-bus --name rides

Also try in the console: open EventBridge → Rules → Create rule on the default bus, choose AWS events, pick EC2 and EC2 Instance State-change Notification, and use the sandbox to test the pattern against the sample event. Then stop a test instance and check the rule’s MatchedEvents and Invocations metrics in CloudWatch.

#Summary

Key takeaways

  • EventBridge (formerly CloudWatch Events) = serverless event bus: events in, rules with event patterns match them, up to 5 targets per rule run. Producers and consumers are decoupled.
  • An event is JSON: source, detail-type, detail, account, region, time. Up to 1 MB since January 2026 (previously 256 KB).
  • Default bus: AWS service events (and CloudTrail API calls) for free. Custom bus: your applications. Partner bus: SaaS partners (Datadog, Auth0, Zendesk, Shopify…). S3 sends events directly when enabled on the bucket.
  • Patterns: fields AND, values OR, exact and case-sensitive; operators prefix, suffix, anything-but, numeric, exists, equals-ignore-case, cidr, wildcard, $or. An event matching no rule simply disappears.
  • Targets: Lambda, SQS, SNS, Step Functions, Kinesis, Firehose, ECS, Batch, SSM, another bus, API destinations… Input transformer to reshape. Retry policy default 24 hours / 185 attempts, then drop or DLQ (standard SQS); permission errors are not retried.
  • Target permissions: resource-based policy for Lambda, SNS, SQS, API Gateway, CloudWatch Logs; IAM role for Kinesis, Step Functions, ECS, SSM and others.
  • Scheduler (recommended): time zones, one-time schedules, millions of schedules, 270+ services. Legacy scheduled rules: default bus, UTC only.
  • Cross-account: resource-based policy on the receiving bus (account or aws:PrincipalOrgID), IAM role on the sender, one hop only; cross-Region with a bus as target. Archive (all or filtered, days or indefinite) + replay after a bug fix. Schema registry + discovery + code bindings. Pipes: point-to-point source → filter → enrichment → target, no code.