TypeScript's structural type system, union types, and first-class async support make it particularly well-suited for CQRS and Event Sourcing implementations. Discriminated unions provide compile-time safety for event handling, and the Node.js ecosystem offers excellent options for event stores and message brokers. This guide covers building a production-grade CQRS/ES system in TypeScript from the ground up.
Core Type Definitions
TypeScript's type system shines when modeling domain events. Discriminated unions ensure exhaustive event handling at compile time.
The discriminated union on the type field lets TypeScript narrow event types in switch statements, catching missing handlers at compile time.
Event Store Implementation
A PostgreSQL-backed event store with optimistic concurrency control and JSONB storage for event payloads.
Aggregate Implementation
The aggregate encapsulates domain logic using the evolve pattern — a pure function that produces new state from current state and an event.
Command Handler
The command handler orchestrates aggregate loading, command execution, and event persistence.
Need a second opinion on your system design architecture?
I run free 30-minute strategy calls for engineering teams tackling this exact problem.
Book a Free CallProjection Engine
A polling-based projection engine that processes events from the global stream and updates read models.
Query Service
Testing
Conclusion
TypeScript brings unique advantages to CQRS and Event Sourcing: discriminated unions catch missing event handlers at compile time, the evolve pattern produces naturally pure state transitions, and async/await simplifies projection consumer code. The PostgreSQL-backed event store with NOTIFY provides a solid foundation that scales to tens of thousands of events per second before you need to consider specialized infrastructure.
Build your event types first, validate them with the type system, and let the compiler guide your aggregate and projection implementations. The investment in precise type definitions pays dividends across every component of the system.