Adapters

@stateledger/drizzle — Drizzle adapter for Postgres

Install

bash
yarn add @stateledger/core @stateledger/drizzle
Postgres 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.