MikroORM
@postel/mikro-orm — run Postel's storage through your existing MikroORM EntityManager (Postgres, MySQL, or SQLite).
@postel/mikro-orm is an ORM adapter: hand Postel your MikroORM instance (or its EntityManager) and it issues its storage queries through the connection's raw execute, so outbox writes share your connection and transactions. No Postel entities are required in your schema.
pnpm add @postel/mikro-orm @mikro-orm/corenpm install @postel/mikro-orm @mikro-orm/coreyarn add @postel/mikro-orm @mikro-orm/corebun add @postel/mikro-orm @mikro-orm/corePlus your MikroORM driver — @mikro-orm/postgresql, @mikro-orm/mysql, or @mikro-orm/better-sqlite.
import { MikroORM } from "@mikro-orm/postgresql";
import { Postel } from "@postel/core";
import { MikroOrmStorage } from "@postel/mikro-orm";
import { config } from "./config.js";
const orm = await MikroORM.init({
clientUrl: config.databaseUrl,
entities: ["./entities"], // your entities
});
export const postel = Postel({
outbound: {
storage: MikroOrmStorage({ orm, dialect: "postgres" }),
},
});Options
| Option | Notes |
|---|---|
orm / em | Your MikroORM instance, or an EntityManager. Postel talks to the underlying connection with raw SQL. |
dialect | "postgres", "mysql", or "sqlite" — selects the reservation strategy, capability flags, and column codecs. |
autoMigrate | Run migrations on first use (default true). |
clock | Inject a clock for deterministic time in tests. |
@mikro-orm/core 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 transaction context 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.