Introduction
Amazon EventBridge is AWS's serverless event bus that decouples sources (S3, API Gateway, SaaS) from targets (Lambda, Step Functions). In 2026, it excels in planetary-scale event-driven architectures, with <100ms latency and 100M+ events/second without provisioning. Unlike SQS/SNS, EventBridge features a native event schema registry and Pipes for real-time transformation and routing of event streams—ideal for microservices or IoT.
Why adopt it? Picture an e-commerce site: an S3 upload triggers an EventBridge rule filtering object.key for 'images/', routes to a resizing Lambda, then a Pipe enriches with DynamoDB data before Step Functions. This expert CDK tutorial deploys a full setup: custom bus, pattern-matching rule, Lambda target, schema registry, and filtering/transformation Pipe. Result: zero infrastructure maintenance and built-in CloudWatch monitoring. Ready to scale? (128 words)
Prerequisites
- AWS account with IAM admin (or CDK roles)
- AWS CLI v2 configured (
aws configure) - Node.js 20+ and CDK 2.140+ (
npm i -g aws-cdk) - Advanced knowledge of TypeScript, Lambda, and AWS events
- us-east-1 region (modifiable in code)
Initialize the CDK project
mkdir eventbridge-expert && cd eventbridge-expert
npm init -y
npm install aws-cdk-lib constructs
npm install -D @types/node ts-node cdk-nag typescript
cdk init app --language typescript
npm install @aws-cdk/aws-lambda-nodejs
mkdir lambda-handlers && touch lambda-handlers/index.ts
cdk context --clearThis script sets up a complete TypeScript CDK project, installs essential libs (CDK core, Lambda Node.js), and prepares directories. cdk-nag enables automatic security checks. Avoid yarn for CI/CD compatibility; test with cdk ls after init.
Understanding the base stack
We create a custom EventBus to isolate events from a SaaS partner (e.g., Stripe webhooks). A rule matches JSON patterns like {"detail-type": ["PaymentSucceeded"]}. The target is an asynchronous Node.js Lambda. Later: schema registry for validation and Pipes for enrichment.
Create the EventBus and Lambda target
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as events from 'aws-cdk-lib/aws-events';
import * as targets from 'aws-cdk-lib/aws-events-targets';
import * as lambda from 'aws-cdk-lib/aws-lambda-nodejs';
import * as logs from 'aws-cdk-lib/aws-logs';
export class EventBridgeStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const eventBus = new events.EventBus(this, 'CustomEventBus', {
eventBusName: 'ExpertEventBus',
});
const handler = new lambda.NodejsFunction(this, 'EventHandler', {
runtime: lambda.Runtime.NODEJS_20_X,
handler: 'index',
entry: 'lambda-handlers/index.ts',
logRetention: logs.RetentionDays.ONE_WEEK,
});
eventBus.grantPutEventsTo(handler);
}
}This stack defines a named EventBus and a Lambda handler with rotating logs. grantPutEventsTo allows the Lambda to emit events (useful for chaining). Pitfall: without a unique eventBusName, cross-account conflicts occur; use cdk-nag to check Least Privilege.
Implement the Lambda handler
import { APIGatewayProxyHandler } from 'aws-lambda';
import { Context } from 'aws-lambda';
export const handler: APIGatewayProxyHandler = async (event: any, context: Context) => {
console.log('Event reçu:', JSON.stringify(event, null, 2));
const detail = event.detail || {};
if (detail.type === 'PaymentSucceeded') {
// Logique métier : update DynamoDB, notifier Slack
console.log(`Paiement ID ${detail.paymentId} traité avec succès.`);
}
return {
statusCode: 200,
body: JSON.stringify({ message: 'Event processed', eventId: event.id }),
};
};Handler parses the standard EventBridge event (with id, detail). Real-world example: filters PaymentSucceeded for e-commerce. Add try/catch for Dead Letter Queue; test locally with sam local invoke before deployment.
Add a rule with pattern matching
EventBridge rules filter using JSONata-like patterns. Example: match only payments >$100 from a specific source. Associate with the Lambda via target.
Define the rule and target
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as events from 'aws-cdk-lib/aws-events';
import * as targets from 'aws-cdk-lib/aws-events-targets';
import * as lambda from 'aws-cdk-lib/aws-lambda-nodejs';
import * as logs from 'aws-cdk-lib/aws-logs';
export class EventBridgeStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const eventBus = new events.EventBus(this, 'CustomEventBus', {
eventBusName: 'ExpertEventBus',
});
const handler = new lambda.NodejsFunction(this, 'EventHandler', {
runtime: lambda.Runtime.NODEJS_20_X,
handler: 'index',
entry: 'lambda-handlers/index.ts',
logRetention: logs.RetentionDays.ONE_WEEK,
});
eventBus.grantPutEventsTo(handler);
const rule = new events.Rule(this, 'PaymentRule', {
eventBus,
eventPattern: {
source: ['stripe.com'],
'detail-type': ['PaymentSucceeded'],
detail: {
amount: [{ numeric: ['>', 100] }],
},
},
});
rule.addTarget(new targets.LambdaFunction(handler, {
event: events.RuleTargetInput.fromEventPath('$.detail'),
}));
}
}Rule matches source: stripe.com, detail-type, and amount >100. fromEventPath passes $.detail to Lambda (input transformer). Advanced: patterns support exists, prefix. Avoid overly broad patterns (replay event costs).
Deploy the CDK stack
cdk bootstrap aws://$(aws sts get-caller-identity --query Account --output text)/us-east-1
cdk synth
cdk deploy --require-approval never
aws events list-rules --event-bus-name ExpertEventBus --region us-east-1
aws lambda list-functions --function-version LATEST --region us-east-1bootstrap prepares the CDK environment; synth/deploy pushes the stack. Verify rules/Lambdas via CLI. Pitfall: --require-approval never for CI; add --outputs-file stack.json for ARNs post-deploy.
Integrate schemas and Pipes
Schema Registry validates events at runtime (OpenAPI/JSON Schema). Pipes transform (Filter/Enrich) before the target, like a Stream API Gateway.
Add schema registry
{
"title": "PaymentSucceeded",
"type": "object",
"required": ["paymentId", "amount"],
"properties": {
"paymentId": { "type": "string" },
"amount": { "type": "number", "minimum": 0 },
"status": { "type": "string", "enum": ["succeeded", "failed"] }
}
}JSON Schema for validation. Import via Console/AWS CLI: aws eventbridge put-event-source-mapping. Associate with rule for auto-generated TypeScript codegen. Great for cross-team contracts.
Implement a transformation Pipe
import * as pipes from 'aws-cdk-lib/aws-pipes';
// ... (code précédent +)
const pipe = new pipes.CfnPipe(this, 'PaymentPipe', {
source: eventBus.eventBusArn,
target: handler.functionArn,
roleArn: pipeRole.roleArn,
sourceParameters: {
eventBridgeParameters: {
source: eventBus.eventBusName,
},
},
filterCriteria: {
filter: {
and_all: [
{ numeric: ['>', 100, '$.detail.amount'] },
{ prefix: ['pay_', '$.detail.paymentId'] },
],
},
},
});
pipe.node.addDependency(rule);Pipe filters amount>100 AND paymentId prefix 'pay_', routes to Lambda. CfnPipe for 2026 features (CDK L2 in beta). Create pipeRole IAM beforehand. Advantage: built-in retry/backpressure vs. simple rules.
Test the event via CLI
EVENT_DATA='{"Source":"stripe.com","DetailType":"PaymentSucceeded","Detail":{"paymentId":"pay_123","amount":150,"status":"succeeded"}}'
aws events put-events --entries "{\"EventBusName\":\"ExpertEventBus\",\"Source\":\"test\",\"DetailType\":\"PaymentSucceeded\",\"Detail\":\"$EVENT_DATA\"}" --region us-east-1
echo "Vérifiez CloudWatch Logs du handler Lambda"Puts a mock event; matches the rule/Pipe. Detail is JSON-stringified. Scale with --entries array. Debug: aws logs filter-log-events --log-group-name /aws/lambda/EventHandler.
Best practices
- IaC only: CDK/Terraform for versioning/replay; avoid Console for prod.
- Precise patterns: Use
numeric,existsfor <1% false positives; test with Event Simulator. - Dead Letter Queue: Attach SQS to rules/Pipes for 100% delivery (max 185 retries).
- Cross-account: Share buses via RAM; audit logs via EventBridge Audit.
- Costs: $1/million events; archive >90d with replay.
Common errors to avoid
- Pattern syntax:
detail: { numeric: ['>', 100] }without$path → no match; validate via Console simulator. - Permissions: Missing
lambda:InvokeFunctionon rule role → silent fail; usecdk-nag Suppresswisely. - Schema mismatch: Non-conforming event dropped without log; enable Event validation + DLQ.
- Pipe loops: Target emits to same bus → infinite; break with
source filter.
Next steps
- Official docs: AWS EventBridge Developer Guide
- Advanced patterns: EventBridge Pipes samples
- Boost your skills with our AWS Learni trainings: CDK Expert & Serverless Architect.
- Integrate with Bedrock for AI event routing (2026 preview).