Install
bash
yarn add @stateledger/core @stateledger/drizzlePostgres only. The adapter uses Postgres-specific advisory locks and index features.
Set up the transitions table
The Drizzle adapter ships with a schema helper you can call from a one-off setup script or paste into a Drizzle migration file.
typescript
import { STATELEDGER_SCHEMA_SQL } from "@stateledger/drizzle";
import { db } from "./db";
import { sql } from "drizzle-orm";
await db.execute(sql.raw(STATELEDGER_SCHEMA_SQL));For production, prefer to embed the SQL into a versioned Drizzle migration (drizzle-kit generate) instead of running it at boot.
Create the adapter
typescript
import { drizzle } from "drizzle-orm/postgres-js";
import postgres from "postgres";
import { createDrizzleAdapter } from "@stateledger/drizzle";
const client = postgres(process.env.DATABASE_URL!);
const db = drizzle(client);
const adapter = createDrizzleAdapter(db);
const order = orderMachine.for("ord_9042", {
adapter,
actor: "warehouse:node-01",
});Inside a transaction
Wrap your business change and the state transition in a single Drizzle transaction so they commit or roll back together.
typescript
await db.transaction(async (tx) => {
// Business write
await tx.update(orders)
.set({ shippedAt: new Date(), trackingId })
.where(eq(orders.id, "ord_9042"));
// State transition on the SAME tx
const order = orderMachine.for("ord_9042", {
adapter: createDrizzleAdapter(tx),
actor: "warehouse:node-01",
});
await order.transitionTo("shipped", {
metadata: { trackingId, carrier: "DHL" },
});
});Reading history
typescript
const order = orderMachine.for("ord_9042", { adapter });
const current = await order.readCurrent();
// { state: "shipped", actor: "warehouse:node-01", at: <Date>, metadata: {...} }
const history = await order.readHistory();
// oldest first: [ picked → packed → shipped ]When to choose Drizzle vs Prisma
Both adapters give you identical stateledger behaviour. Pick the one that matches your existing ORM. If you’re starting fresh: Drizzle is lighter and TypeScript-native, Prisma has better tooling around migrations and Studio. Either is fine for stateledger.