# Compatibility

The same suite runs against postgres.js, node-postgres, Bun.sql, and PGlite. `pass` means the case ran and matched. `skip` means the adapter does not offer that behaviour. `fail` means it ran and did not match. `not-run` means the suite did not reach it. The command is [`okm driver test`](/docs/reference/cli/check#driver-test). The cells below are generated from `tests/driver-suite.test.ts` and `tests/error-suite.test.ts`. The floor is [Minimum Postgres](/docs/schema/the-schema#minimum-postgres).

Supported majors are Postgres 15, 16, 17, and 18. The floor is 15: Postgres 13 is past end of life, 14 ends in November 2026, and 15 gives us features we can use later. `connect()` refuses an older server with OKM1803. `minPostgres` is 15, 16, 17, or 18. `requires: { postgres: ">=17" }` is the same floor and is deprecated. Identity columns need Postgres 10. A bare `t.id()` stores `gen_random_uuid()`, which is built in from Postgres 13. An explicit `uuidv7()` needs Postgres 18. A pull request runs Postgres 18 when the diff touches dialects, migrate, or runtime. `bun run verify` runs the suite on this machine. A push to main, the nightly run, and a release cover each supported major. A failure on an older major in this list stays in the run.

Postgres: native. Since 18. Proof passes (`proof:type.uuidv7`).


PGlite runs in the check job. The in-process wire server runs in the check job. postgres.js, node-postgres, and Bun.sql run in the postgres job (`REQUIRE_DOCKER=1`). Bun.sql runs only under Bun. A skip means the adapter did not declare the capability that case needs. node-postgres and Bun.sql do not describe a statement without running it. Bun.sql does not surface RAISE NOTICE and does not abort an in-flight statement. PGlite has no socket to cut, so COMMIT loss (`r2.commit-loss`, `r2.batch-commit-loss`) is `unsupported` in `okm driver test`, with that reason. It is not a silent skip.

Neon is not a column in this table. postgres.js and node-postgres pointed at Neon endpoints are not columns either, and those results stay unclassified. `okmodel/pg/neon` has its own connect gate. It is checked locally when its credentials are set and skipped in CI. WebSocket mode is interactive. HTTP mode is `transactions: "batch"`: `tx()` is refused. A transaction-mode pooler does not promise session state. COMMIT loss is `unsupported` (`no socket to cut`) because the harness cut is a TCP relay. A result that never arrives is still `outcome_unknown`.

| Case | postgres.js | node-postgres | Bun.sql | PGlite |
| --- | --- | --- | --- | --- |
| execute returns rows | pass | pass | pass | pass |
| keeps null as null | pass | pass | pass | pass |
| keeps timestamps as wire text | pass | pass | pass | pass |
| keeps numeric as wire text | pass | pass | pass | pass |
| keeps bigint as wire text | pass | pass | pass | pass |
| keeps json as wire text | pass | pass | pass | pass |
| keeps arrays as wire text | pass | pass | pass | pass |
| returns notices | pass | pass | skip | pass |
| batch commits every statement | pass | pass | pass | pass |
| batch rolls back a failure at each position | pass | pass | pass | pass |
| batch reports a deferred constraint at commit | pass | pass | pass | pass |
| rejects a pre-aborted signal before the statement | pass | pass | pass | pass |
| cancels an in-flight statement | pass | pass | skip | skip |
| times out an in-flight statement | pass | pass | skip | skip |
| cancels a batch and rolls it back | pass | pass | skip | skip |
| times out a batch and rolls it back | pass | pass | skip | skip |
| runs a batch inside a transaction on a savepoint | pass | pass | pass | pass |
| clears a custom setting and an advisory lock on release | pass | pass | pass | pass |
| reports pool stats | pass | pass | pass | pass |
| close rejects a later execute | pass | pass | pass | pass |
| acquire timeout is OKM1846 and does not use another pool | pass | pass | pass | pass |
| describes a statement | pass | skip | skip | pass |
| streams rows | pass | pass | pass | skip |
| delivers a notification | pass | pass | pass | pass |
| maps a unique violation | pass | pass | pass | pass |
| maps a not-null violation | pass | pass | pass | pass |
| maps a check violation | pass | pass | pass | pass |
| maps a foreign key violation | pass | pass | pass | pass |
| maps an exclusion violation | pass | pass | pass | pass |
| maps serialization, deadlock, and lock timeout | pass | pass | pass | pass |
| maps a statement timeout | pass | pass | pass | pass |
| maps an in-flight statement timeout | pass | pass | skip | skip |
| maps a cancelled call and does not retry it | pass | pass | pass | pass |
| maps a connection failure | pass | pass | pass | pass |
| carries batchIndex on a batch failure and null at commit | pass | pass | pass | pass |


The public type surface (`scripts/api-surface.ts`) and the consumer fixtures (`*.test-d.ts` files the required typecheck includes) compile with TypeScript 7.0.2 (`tsc`, required, `bun run typecheck`). The same files compile with TypeScript 6.0.3 through the dev-only `typescript-editor` package (`bun run ts6:check`). That run is not part of `bun run check`. Nothing in `src/` imports the TypeScript compiler API. TypeScript 7.0 has no stable programmatic API until 7.1.


| Next | You use it for |
| --- | --- |
| [Drivers](/docs/operate/drivers) | Pick a driver and a `prepared` mode. |
| [Minimum Postgres](/docs/schema/the-schema#minimum-postgres) | What PostgreSQL 15 through 18 can run. |
| [driver test](/docs/reference/cli/check#driver-test) | Run the suite that fills this table. |

Index: [/llms.txt](/llms.txt)
