# TypeORM



`@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.

<Install packages="@postel/typeorm typeorm" />

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

```ts title="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 [#options]

| Option        | Notes                                                                                                           |
| ------------- | --------------------------------------------------------------------------------------------------------------- |
| `dataSource`  | The 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. |
| `autoMigrate` | Run migrations on first use (default `true`).                                                                   |
| `clock`       | Inject 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](/docs/storage#dialects-and-compatible-databases).

## Shared transactions [#shared-transactions]

Open the transaction with TypeORM as usual and pass the transaction's `QueryRunner` to `send()` as `tx`, so the outbox insert commits atomically with your business writes:

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

## Migrations [#migrations]

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