Skip to content

Drizzle (PostgreSQL) Driver

The Drizzle driver persists events to a PostgreSQL database using Drizzle ORM. It is a recommended choice for production.

import { createEventStore, createAggregateRoot } from '@requence/event-sourcing/drizzle'
import { drizzle } from 'drizzle-orm/node-postgres'
const db = drizzle(process.env.DATABASE_URL!)
const eventStore = createEventStore({
database: db,
aggregateRoots: [userAggregateRoot],
})

The driver uses a dedicated event_sourcing PostgreSQL schema with the following tables:

TablePurpose
eventsAppend-only event log with position, stream, and metadata
checkpointsLast-processed position (and optimistic-concurrency version) per projection/process manager
aggregate_root_snapshotsCached aggregate state for fast rehydration
projection_snapshotsCached projection state for snapshot-based projections
projection_applied_eventsCounter for snapshot frequency tracking

The table definitions are exported from @requence/event-sourcing/drizzle/postgres for use in Drizzle migrations:

import {
events,
checkpoints,
aggregateRootSnapshots,
projectionSnapshots,
projectionAppliedEvents,
} from '@requence/event-sourcing/drizzle/postgres'
import { redisLock } from '@requence/event-sourcing/redis'
import Redis from 'ioredis'
const redis = new Redis(process.env.REDIS_URL)
const eventStore = createEventStore({
// Required — Drizzle database instance or factory
database: db,
// Required — one or more aggregate roots
aggregateRoots: [user, project],
// Optional — distributed lock for multi-instance deployments
lock: redisLock(redis),
// Optional — disable automatic initialization
autoInit: false,
// Optional — callback invoked after events are appended
onEventsAppended(events) {
// e.g. broadcast via WebSocket
},
// Optional — replay and refresh progress callbacks
onProjectionReplay: { /* ... */ },
onProcessManagerRefresh: { /* ... */ },
// Optional — post-process events before persistence
postProcessEvent(event, aggregateRoot) {
return event
},
})