0x55aa
← Back to Blog

AWS EventBridge: The Event Bus That Ties Your Entire AWS Account Together âšĄðŸšŒ

â€Ē9 min read

AWS EventBridge: The Event Bus That Ties Your Entire AWS Account Together âšĄðŸšŒ

Real talk: When I first built a serverless e-commerce backend on AWS, I wired everything together with direct Lambda invocations. Service A called Service B. Service B called Service C. Service C called A again (yes, circular - don't ask). It was spaghetti. It was beautiful. It was a disaster waiting to happen.

Then a senior engineer looked at my architecture diagram and said, "Have you tried EventBridge?"

Reader, it changed my life. ðŸâžĄïļðŸ›ïļ

What Even Is EventBridge? ðŸĪ”

Think of it as the air traffic controller of your AWS account.

Without EventBridge:

Order Service → directly calls → Email Service
Order Service → directly calls → Inventory Service
Order Service → directly calls → Analytics Service
Order Service → directly calls → Fraud Detection
# Coupled to everything. Change one thing, break everything.

With EventBridge:

Order Service → publishes event → EventBridge Bus
                                      ↓
                          ┌───────────────────────┐
                          ↓           ↓            ↓
                    Email Lambda  Inventory  Analytics

One publisher, infinite subscribers. Zero coupling. Your Order Service doesn't know (or care) who's listening. ðŸŽŊ

The EventBridge vs SNS vs SQS Confusion (Finally Settled) ðŸĨŠ

Everyone asks this. Here's the honest breakdown:

Tool Best For
SQS Work queues, retry logic, "process this exactly once"
SNS Fan-out push notifications, fire-and-forget broadcasts
EventBridge Routing events between AWS services, SaaS integrations, complex filtering

Key EventBridge superpower: It understands event content. You can route {"status": "payment_failed"} to one Lambda and {"status": "payment_success"} to a completely different one - based on the actual event data. SNS can't do that cleanly. SQS doesn't even try.

In production, I've deployed all three. EventBridge is what glues them together. 🔗

The Setup That Saved Our E-Commerce Backend 🛒

When architecting on AWS, I learned that the cleanest pattern is publishing events from every service boundary. Here's what our order flow looks like now:

Step 1: Publish the event (from Order Service Lambda)

import { EventBridgeClient, PutEventsCommand } from "@aws-sdk/client-eventbridge";

const client = new EventBridgeClient({ region: "us-east-1" });

async function publishOrderEvent(order) {
  await client.send(new PutEventsCommand({
    Entries: [{
      Source: "myapp.orders",
      DetailType: "OrderPlaced",
      Detail: JSON.stringify({
        orderId: order.id,
        userId: order.userId,
        amount: order.total,
        items: order.items
      }),
      EventBusName: "myapp-production"  // Custom bus, not default!
    }]
  }));
}

Step 2: Create routing rules (via Terraform/CDK/Console)

{
  "source": ["myapp.orders"],
  "detail-type": ["OrderPlaced"],
  "detail": {
    "amount": [{ "numeric": [">", 500] }]
  }
}

This rule says: "Route this event only if the order total is over $500."

Different rule for high-value fraud check:

{
  "source": ["myapp.orders"],
  "detail-type": ["OrderPlaced"],
  "detail": {
    "amount": [{ "numeric": [">", 1000] }]
  }
}

Orders over $1000 get routed to fraud detection AND the normal flow. Same event, multiple consumers, zero code changes in Order Service. 🎉

The AWS Service Events You Didn't Know Were Free ☁ïļ

Here's the part that made me actually gasp: AWS services already publish events to EventBridge by default.

EC2 instance changes, RDS snapshots, CodePipeline deployments, S3 Object Lambda events, ECR image pushes - they're all events you can react to.

A serverless pattern that saved us:

// Trigger cleanup Lambda whenever an ECR image is pushed
{
  "source": ["aws.ecr"],
  "detail-type": ["ECR Image Action"],
  "detail": {
    "action-type": ["PUSH"],
    "repository-name": ["myapp-api"]
  }
}

Every time we push a Docker image to ECR, a Lambda automatically:

  1. Scans for old images (keep last 10)
  2. Deletes the rest
  3. Posts to our Slack #deployments channel

Total cost: ~$0. Lambda execution time + 1 EventBridge rule. 💰

Content-Based Filtering: The Real Magic 🊄

This is what separates EventBridge from everything else.

Scenario: Payment service publishes one event type. You need different behavior based on status.

// Payment service publishes this
{
  "source": "myapp.payments",
  "detail-type": "PaymentProcessed",
  "detail": {
    "status": "failed",  // or "success", "refunded"
    "gateway": "stripe",
    "amount": 99.99,
    "customerId": "cust_123",
    "reason": "card_declined"
  }
}

Rule 1 - Route failures to retry queue:

{
  "detail": {
    "status": ["failed"],
    "gateway": ["stripe"]
  }
}

Rule 2 - Route refunds to accounting:

{
  "detail": {
    "status": ["refunded"],
    "amount": [{ "numeric": [">", 50] }]
  }
}

Rule 3 - Route everything to analytics:

{
  "source": ["myapp.payments"]
}

One event. Three destinations. Zero if/else in Payment Service.

When I first built this, I literally deleted 200 lines of routing code from our payment Lambda. The team cheered. 🎊

EventBridge Scheduler: Cron Jobs That Don't Suck ⏰

Buried inside EventBridge is a gem called EventBridge Scheduler. It's cron on steroids.

The old way (CloudWatch Events, which is also EventBridge, confusingly):

# Rate expression - simple but limited
rate(5 minutes)

# Cron expression - powerful but confusing
cron(0 9 * * ? *)

The new Scheduler way:

// One-time scheduled event (incredible for async workflows!)
await scheduler.send(new CreateScheduleCommand({
  Name: `send-reminder-${orderId}`,
  ScheduleExpression: "at(2026-03-15T09:00:00)",  // One-time!
  Target: {
    Arn: reminderLambdaArn,
    RoleArn: schedulerRoleArn,
    Input: JSON.stringify({ orderId, type: "abandoned-cart" })
  },
  FlexibleTimeWindow: { Mode: "OFF" }
}));

Real use case: When a user abandons their cart, schedule a reminder email for 24 hours later. If they check out before then, delete the schedule.

In production, I've deployed this for ~50k users with zero infrastructure management. No cron servers. No background workers. No "is the scheduler still running?" panic at 3am. 🌙

The SaaS Integration Nobody Talks About ðŸĪ

EventBridge has native integrations with 100+ SaaS products: Shopify, GitHub, Zendesk, Datadog, PagerDuty...

When Stripe processes a payment, it can send events directly to your EventBridge bus - no webhook endpoint needed on your side.

Stripe Event → EventBridge Partner Bus → Your Rules → Your Lambda

I set this up in 20 minutes for our Stripe integration. Previously we had:

  1. A webhook endpoint Lambda
  2. Signature verification code
  3. Event parsing/routing code
  4. Retry logic

Now we have: one EventBridge rule. The rest is AWS's problem.

The Gotchas That Will Bite You ðŸŠĪ

Gotcha #1: Events Are Not Guaranteed To Be Ordered

EventBridge is at-least-once delivery. Two events can arrive out of order. Your consumers must be idempotent.

// Bad: assumes events arrive in order
exports.handler = async (event) => {
  const { status } = event.detail;
  await db.updateOrderStatus(orderId, status);  // What if "completed" arrives before "processing"?
};

// Good: check current state before updating
exports.handler = async (event) => {
  const { status, timestamp } = event.detail;
  await db.updateOrderStatusIfNewer(orderId, status, timestamp);
};

Gotcha #2: Default Bus vs Custom Bus

The default event bus receives AWS service events. Put your custom app events on a custom bus.

# Create your own bus
aws events create-event-bus --name myapp-production

# Use it in your events!
aws events put-events --entries '[{"EventBusName":"myapp-production",...}]'

Why? Keeps AWS noise separate from your app events. Cleaner rules. Cheaper debugging.

Gotcha #3: EventBridge Has A 256KB Event Size Limit

Events bigger than 256KB get rejected. If you're tempted to shove entire database records into events - don't.

A serverless pattern that saved us: Send only the IDs in the event, fetch full data in the consumer.

// Bad: 500KB event, gets rejected
{
  "orderId": "ord_123",
  "orderData": { /* entire order object with 200 line items */ }
}

// Good: tiny event, consumer fetches what it needs
{
  "orderId": "ord_123",
  "eventType": "OrderPlaced"
}

Cost Breakdown (Because You Need To Know) 💰

EventBridge pricing is beautifully cheap:

  • Custom events: $1.00 per million events
  • AWS service events: Free (!)
  • Cross-account events: $1.00 per million
  • EventBridge Scheduler: $1.00 per million scheduled invocations

Real numbers from our production system:

  • ~5M events/month across all services
  • Cost: $5/month
  • What we replaced: A dedicated RabbitMQ cluster at $120/month

That's not a typo. $5 vs $120. EventBridge won. 🏆

Quick Start: Replace Your First Spaghetti Integration 🚀

Before (direct coupling):

// In your Order Lambda - knows too much!
async function handleOrder(order) {
  await emailService.sendConfirmation(order);
  await inventoryService.reserve(order.items);
  await analyticsService.track('order_placed', order);
  await loyaltyService.addPoints(order.userId, order.total);
  // Adding a 5th service means changing THIS file ðŸ˜ą
}

After (EventBridge):

// In your Order Lambda - knows nothing!
async function handleOrder(order) {
  await publishEvent({
    source: "myapp.orders",
    detailType: "OrderPlaced",
    detail: { orderId: order.id, userId: order.userId, total: order.total }
  });
  // Adding a 5th service means zero changes here 🎉
}

Add the 5th, 10th, 20th service? Just create a new EventBridge rule. Your Order Service stays blissfully ignorant. That's the architecture you want.

TL;DR ⚡

EventBridge is the event backbone your AWS account needs if:

  • You have more than 3 services that need to communicate
  • You're tired of direct Lambda-to-Lambda calls creating tight coupling
  • You want to react to AWS service events without polling
  • You're integrating SaaS products and hate writing webhook servers

Avoid it when:

  • You need strict ordering (use Kinesis instead)
  • You need guaranteed exactly-once delivery (use SQS FIFO)
  • Your events are >256KB (rethink your event design)

In production, I've deployed EventBridge as the backbone of a system handling 50k+ events per day. It has never failed. It has never needed a patch. It scales automatically. It costs about as much as a cup of coffee per month. ☕

When architecting on AWS, I learned: The best infrastructure is the kind you forget you're paying for. EventBridge qualifies.

Now go delete that spaghetti! 🍝ðŸ’Ĩ


Have an EventBridge war story or a pattern I missed? Connect on LinkedIn - always happy to talk AWS architecture!

Check out my serverless experiments on GitHub 🚀