Storage

TypeORM

@postel/typeorm — run Postel's storage through your existing TypeORM DataSource (Postgres, MySQL, or SQLite).

@postel/typeorm is an ORM adapter: hand Postel the TypeORM DataSource you already use and it issues its storage queries through it (via QueryRunners + raw SQL), so outbox writes share your connection and transactions. No Postel entities are required in your schema.

pnpm add @postel/typeorm typeorm
npm install @postel/typeorm typeorm
yarn add @postel/typeorm typeorm
bun add @postel/typeorm typeorm

Plus your database driver — pg, mysql2, or better-sqlite3.

lib/postel.ts
import { DataSource } from "typeorm";
import { Postel } from "@postel/core";
import { TypeOrmStorage } from "@postel/typeorm";
import { config } from "./config.js";

const dataSource = new DataSource({ type: "postgres", url: config.databaseUrl });
await dataSource.initialize();

export const postel = Postel({
  outbound: {
    storage: TypeOrmStorage({ dataSource, dialect: "postgres" }),
  },
});

Options

OptionNotes
dataSourceThe initialized TypeORM DataSource you already built. Postel talks to it through QueryRunners + raw SQL.
dialect"postgres", "mysql", or "sqlite" — selects the reservation strategy, capability flags, and column codecs.
autoMigrateRun migrations on first use (default true).
clockInject a clock for deterministic time in tests.

typeorm is a peer dependency. On Postgres and MySQL workers reserve rows under FOR UPDATE SKIP LOCKED; on SQLite in a single statement. MySQL and SQLite poll for dispatch (no LISTEN/NOTIFY); Postgres pushes. The dialect names a SQL family, so wire-compatible engines (MariaDB, PlanetScale, libSQL/Turso, …) work via the matching dialect — see compatible databases.

Shared transactions

Postel({...}).outbound.transaction(cb) hands your callback a connection-bound executor you thread into send(), so the outbox insert commits atomically with your business writes:

await postel.outbound.transaction(async (tx) => {
  await postel.send({ type: "order.created", data: { /* ... */ } }, { tx });
});

Migrations

autoMigrate (default true) runs the canonical migrations through your connection, version-gated and idempotent — or run your own tooling against that schema.

On this page