DEV Community

Cover image for AWS EventBridge: Event Buses and Rules You Can Script from Day One
Bry
Bry

Posted on Originally published at Medium

AWS EventBridge: Event Buses and Rules You Can Script from Day One

Key Points

  • EventBridge charges $1.00 per million custom events published; rule evaluation itself is free, up to 300 rules per bus. The real billing surprise isn't rule count — it's payload size, since events bill in 64 KB chunks and the January 2026 limit increase to 1 MB means one large event can now bill as up to 16.
  • A custom event bus, a rule with a JSON event pattern, and a Lambda target take four CLI commands total. Use InputTransformer on targets to trim events down to only the fields a target needs, rather than forwarding the full body downstream.
  • Archive and replay are cheap to enable and expensive to forget about — archived data bills monthly storage whether or not you ever replay it.

Prerequisites

  • CLI/SDK version tested against: aws-cli/2.35.x
  • An IAM role with events:* and lambda:InvokeFunction permissions
  • A deployed Lambda function to act as a target — the examples use order-processor

Introduction

EventBridge gets pitched as "SNS but smarter" often enough that people underrate how little code it takes to get real value from it. I've stood up event-driven order processing for two different clients using nothing but a custom bus, a handful of pattern-matched rules, and existing Lambda functions — no message broker to run, no queue infrastructure to patch.

The part that doesn't show up in the marketing is the cost mechanic that changed in January 2026: AWS raised the maximum event payload from 256 KB to 1 MB, which sounds like a pure win until you notice events still bill in 64 KB chunks. A single 1 MB event can now bill as 16 separate chunked events at the custom-event rate. That's not a reason to avoid EventBridge — it's a reason to design your event payloads deliberately instead of dumping an entire domain object into detail.

This article builds a working bus, rule, and target from the terminal, and treats the payload mechanic as a design input, not an afterthought.


Bus, Rules, Targets: The Three Pieces

Bus, Rules, Targets: The Three Pieces

Diagram: one bus, multiple rules each matching a different event pattern, each routing to its own target.

A rule without a target does nothing but sit there for free. A rule with a matching event pattern and a wired-up target is what actually moves data. Rules and targets are separate API calls on purpose — one rule can fan out to up to five targets.


Building It From the CLI

# 1. A custom bus — separate from the default bus so your rules
#    only ever see events your own services publish.
aws events create-event-bus --name orders-bus

# 2. A rule matching a specific event pattern on that bus.
aws events put-rule \
  --name order-created-rule \
  --event-bus-name orders-bus \
  --event-pattern '{
    "source": ["orders-service"],
    "detail-type": ["OrderCreated"],
    "detail": {
      "status": ["pending"]
    }
  }'

# 3. Grant the rule permission to invoke the Lambda target.
aws lambda add-permission \
  --function-name order-processor \
  --statement-id eventbridge-invoke \
  --action lambda:InvokeFunction \
  --principal events.amazonaws.com \
  --source-arn "arn:aws:events:us-east-1:123456789012:rule/orders-bus/order-created-rule"

# 4. Wire the rule to the Lambda target.
aws events put-targets \
  --rule order-created-rule \
  --event-bus-name orders-bus \
  --targets '[{
    "Id": "order-processor-target",
    "Arn": "arn:aws:lambda:us-east-1:123456789012:function:order-processor"
  }]'
Enter fullscreen mode Exit fullscreen mode

Four commands, and the bus is live. Publish a test event to confirm the wiring:

aws events put-events --entries '[{
  "Source": "orders-service",
  "DetailType": "OrderCreated",
  "Detail": "{\"orderId\":\"order-abc123\",\"status\":\"pending\",\"total\":49.99}",
  "EventBusName": "orders-bus"
}]'
Enter fullscreen mode Exit fullscreen mode

A successful response returns "FailedEntryCount": 0. If it's 1, check Errors in the same response — the two most common causes are a malformed Detail JSON string or a detail-type/source combination that doesn't match any rule, which fails silently rather than erroring (the event is simply dropped with no matching rule, and EventBridge does not treat that as a failure).


Designing Around the Payload-Chunking Rule

Designing Around the Payload-Chunking Rule

Diagram: EventBridge's per-64KB chunking mechanic, effective with the January 2026 payload limit increase to 1 MB.

The fix isn't "never send large events." It's "don't send more than the target needs." Two concrete patterns:

Send a reference, not the full object. If order-created-rule's target only needs the order ID to go fetch full details itself, publish {"orderId": "order-abc123"} in detail, not the entire order document with line items, customer data, and shipping addresses.

Use InputTransformer to trim before delivery. When the target genuinely needs specific fields from a larger event, extract them at the rule level instead of forwarding everything:

aws events put-targets \
  --rule order-created-rule \
  --event-bus-name orders-bus \
  --targets '[{
    "Id": "order-processor-target",
    "Arn": "arn:aws:lambda:us-east-1:123456789012:function:order-processor",
    "InputTransformer": {
      "InputPathsMap": {
        "orderId": "$.detail.orderId",
        "status": "$.detail.status"
      },
      "InputTemplate": "{\"orderId\": <orderId>, \"status\": <status>}"
    }
  }]'
Enter fullscreen mode Exit fullscreen mode

InputTransformer runs on EventBridge's side before delivery — it doesn't reduce what you're billed for publishing the original event, but it does mean your Lambda isn't parsing (and your logs aren't storing) a payload larger than it needs.


Archive and Replay

Archiving lets you replay events later — useful for reprocessing after a bug fix, or reconstructing state after a downstream outage. It's cheap per operation and easy to forget about entirely.

aws events create-archive \
  --archive-name orders-archive \
  --event-source-arn arn:aws:events:us-east-1:123456789012:event-bus/orders-bus \
  --retention-days 30
Enter fullscreen mode Exit fullscreen mode
Component Price
Archive processing $0.10/GB archived
Archive storage $0.023/GB-month
Replayed events $1.00/million (same as custom event rate)

Storage bills every month an archive exists, whether or not anything ever gets replayed from it. Set --retention-days deliberately — 30 days is a reasonable default for operational replay; longer retention should be a conscious compliance or audit decision, not the default you forgot to change.


Common Mistakes

Mistake 1: Publishing to the default bus for everything
The default bus receives AWS service events too. Mixing your application events into it makes rule patterns harder to write precisely and makes the bus noisier to reason about. Use a custom bus per domain area.

Mistake 2: Assuming a failed match throws an error
It doesn't. An event with no matching rule is dropped silently — put-events still returns success. Test your event patterns against real sample events before relying on them in production.

Mistake 3: Forwarding entire event payloads to every target
This is both a cost issue (larger payloads, more chunked billing on any downstream re-publish) and a coupling issue — targets that receive more than they need tend to accumulate implicit dependencies on fields nobody documented.

Mistake 4: Enabling archive without a retention policy decision
Storage costs accrue every month regardless of replay activity. An archive with no retention limit and no owner is exactly the kind of AWS bill line item nobody can explain six months later.


Production Considerations

Performance: Rule matching is fast and free regardless of rule count up to the 300-per-bus limit. If you're approaching that limit, it's usually a sign you need multiple buses segmented by domain, not one bus straining to model everything.

Security: Use resource-based policies on the event bus (put-permission) to control which accounts or services can publish, rather than relying solely on IAM policies at the producer side.

Cost: Re-run the payload math whenever a producer's event shape grows. A field added "just in case" on a high-volume event source compounds fast at the chunked billing rate.

Monitoring: CloudWatch metrics on TriggeredRules, FailedInvocations, and ThrottledRules are free and on by default — set an alarm on FailedInvocations per target, since a misconfigured target fails silently from the publisher's perspective.


Full Example: Teardown Script

#!/usr/bin/env bash
set -euo pipefail

BUS_NAME="${BUS_NAME:-orders-bus}"
RULE_NAME="${RULE_NAME:-order-created-rule}"

aws events remove-targets --rule "$RULE_NAME" --event-bus-name "$BUS_NAME" --ids order-processor-target
aws events delete-rule --name "$RULE_NAME" --event-bus-name "$BUS_NAME"
aws events delete-archive --archive-name orders-archive || true
aws events delete-event-bus --name "$BUS_NAME"

echo "Torn down $BUS_NAME and its rules."
Enter fullscreen mode Exit fullscreen mode

Full source including the sample Lambda target and pattern-matching tests: GitHubcloud-apis/aws-eventbridge-cli/


Conclusion

EventBridge is one of the fastest AWS services to script from zero — a working bus, rule, and target is four commands. The part worth designing around deliberately is payload size: with the 2026 increase to a 1 MB event limit, it's easy to publish something large enough to bill as multiple events without noticing. Send references and trim payloads with InputTransformer rather than forwarding full objects downstream, and treat archive retention as a decision you make on purpose, not a default you forgot existed.


Further Reading


If this helped, a like and a follow are appreciated — and if you've solved this differently, drop a comment, I'd like to hear it.

Bry Writes Code — cloud and API infrastructure specialist. Designing an event-driven architecture on AWS? Get in touch.

Top comments (0)