Implementing Event-Driven Architecture in Next.js

Core Implementation Strategy

1. Node.js Event System

Use Node.js' native EventEmitter for basic event handling:

// lib/eventBus.js
import { EventEmitter } from 'events';
export const eventBus = new EventEmitter();

2. Serverless Event Routing

Key integrations:

3. Reactive Frontend

Custom hook for component communication:

// hooks/useEvent.ts
export const useEvent = <T>(eventName: string, callback: (data: T) => void) => {
  const dispatch = (data: T) => window.dispatchEvent(new CustomEvent(eventName, { detail: data }));
  useEffect(() => {
    const handler = (e: CustomEvent<T>) => callback(e.detail);
    window.addEventListener(eventName, handler as EventListener);
    return () => window.removeEventListener(eventName, handler as EventListener);
  }, []);
  return dispatch;
};

Category Tools Use Case
Databases Supabase, PlanetScale, NeonDB Persistent event storage
Caching Upstash Redis, Vercel KV Event state caching
Messaging QStash, AWS SNS/SQS, Pusher Cross-service communication
Monitoring Sentry, Datadog Pipeline observability
State Management Zustand, Redux Toolkit Global state handling

Key Implementation Patterns

1. Event Sourcing/CQRS

// pages/api/events.ts
export async function POST(req: Request) {
  const event = await req.json();
  await persistEvent(event);
  await updateReadModel(event);
}

2. Reliable Delivery

// Serverless function handler
export default async (req, res) => {
  try {
    await processEvent(req.body);
    await qstash.resend(req);
  } catch (error) {
    await deadLetterQueue.add(req.body);
  }
};

3. Real-Time UI Updates

// components/RealTimeFeed.js
useEffect(() => {
  const ws = new WebSocket('wss://api.your-app.com/events');
  ws.onmessage = (event) => {
    const data = JSON.parse(event.data);
    eventBus.emit(data.type, data.payload);
  };
}, []);

Best Practices

  1. Event Design

    {
      "$schema": "http://json-schema.org/draft-07/schema#",
      "type": "object",
      "properties": {
        "eventId": { "type": "string" },
        "timestamp": { "type": "number" }
      }
    }
    
  2. Performance Optimization

    • Batch process events in serverless functions
    • Use Redis streams for high-throughput scenarios
  3. Observability

    eventEmitter.on('user:registered', (data) => {
      Sentry.addBreadcrumb({
        message: 'User registration event',
        data
      });
    });
    

Example Architecture

E-Commerce Product Flow

graph LR
A[Admin UI] -->|emit| B[ProductUpdatedEvent]
B --> C[(Event Store)]
C --> D[Search Indexer]
C --> E[Email Service]
C --> F[Cache Invalidation]

Implementation Features