Check

The first connection checks the server, the catalog hash, and the floor.

schema is required. The schema types the client. db.connected resolves when the check finishes. A query waits for it. A transaction and a batch wait too.

minPostgres is the floor connect reads. With no floor, the minimum is 15. A named floor is 15, 16, 17, or 18. A server below that major is refused. A major below 15 is refused when schema() runs. The floor runs after the hash check.

signal and timeout on this check are Timeouts. A preset name that is a client method or reserved is checked before the first query. The names are on Presets.

ResultWhat happens
Not PostgreSQLOKM1801
okm_meta has no hash, and requireMeta is setOKM1520
Equal catalog hashesReturns without reading okm_history.

okm_meta is read in the namespace defineConfig placed. public uses the unqualified name. okm build writes .okm/namespace for any other schema, and connect reads that file from catalogDir or .okm. A missing file keeps the public query. | Ahead by expand migrations | The drift check returns. The client opens when the floor passes. | | Ahead by a contract migration, or behind | OKM1520 | | Below 15, and the schema names no minPostgres | OKM1803 | | Below the schema minPostgres | OKM1802 |

schema

db.ts
import { connect } from "okmodel/pg/postgresjs";
import { schema, table, t } from "okmodel/pg";

const notes = table("notes", {
  id: t.identity(),
  title: t.text(),
});

const app = schema({ tables: [notes] }); 

export const db = connect(process.env.DATABASE_URL!, { schema: app }); 

server

version() must start with PostgreSQL.

OKM1801

The server is not PostgreSQL. The schema dialect is postgres.

floor

A server below 15, when no floor is named, is OKM1803.

OKM1803

The server is PostgreSQL 14. This schema needs PostgreSQL 15 or higher (minPostgres: 15).

A server below the named floor is OKM1802.

OKM1802

The server is PostgreSQL 16. This schema needs PostgreSQL 17 or higher (minPostgres: 17).

A value that is not an allowed major is refused when schema() runs. Minimum Postgres lists the majors. requires: { postgres: ">=17" } is the same floor and is deprecated.

Require meta

requireMeta fails connect when okm_meta has no catalog hash. It is a connect option. The target name and NODE_ENV do not turn it on. Set this on a production connection. Only true turns it on. false is the same as omitted. protected on a migrate target does not affect connect().

ValueResult
omittedA database with no recorded hash skips the drift check. An existing database can adopt OKModel.
trueA missing hash is OKM1520.

Leave requireMeta out. A database with no recorded hash skips the drift check. A null hash and an empty hash are both no catalog hash. An existing database can adopt OKModel. The version check still runs.

A recorded hash still runs the drift check, below.

requireMeta: true fails connect when the hash is missing. That throw is OKM1520. It happens before the drift check and before the version check.

db.ts
import { connect } from "okmodel/pg/postgresjs";
import { schema, table, t } from "okmodel/pg";

const notes = table("notes", {
  id: t.identity(),
  title: t.text(),
});

const app = schema({ tables: [notes] });

export const db = connect(process.env.DATABASE_URL!, {
  schema: app,
  requireMeta: true, 
});

OKM1520

A missing hash is okm_meta has no catalog hash. The fix is Apply migrations so okm_meta records the catalog, or omit requireMeta to adopt this database.

Catalog

catalog and catalogDir exist so this check can load the code's catalog. The value is { text, hash }. text is the catalog JSON. hash is that hash. The JSON is checked only when the database hash differs.

Connect takes the first row that applies.

SourceCode hash
cataloghash on { text, hash }.
a non-empty catalog.hashThe file. A mismatch reads catalog.json once per process.
a missing or empty catalog.hashThe schema catalog.

When catalog is set, hash is the code's catalog hash. A difference loads text once per process. The load checks text against hash. Concurrent connects share that load.

catalogDir is the directory of catalog.hash and catalog.json. A trailing / or \ is removed, so the joined file name is one path. Connect reads this directory when catalog is omitted. okm build writes those two files.

db.ts
import { connect } from "okmodel/pg/postgresjs";
import { schema, table, t } from "okmodel/pg";

const notes = table("notes", {
  id: t.identity(),
  title: t.text(),
});

const app = schema({ tables: [notes] });

export const db = connect(process.env.DATABASE_URL!, {
  schema: app,
  catalogDir: ".okm", 
});

Omitted, the directory is .okm under the process cwd. When process.cwd is missing, the directory is ./.okm.

A missing hash file hashes the schema catalog instead. catalog.json stays unread.

When catalog is omitted, connect reads catalog.hash from that directory. UTF-16 throws OKM1027 before the schema catalog is hashed. A leading BOM is stripped. Carriage returns are removed. The hash is then trimmed, so a trailing newline is dropped. An empty result hashes the schema catalog instead.

A hash that remains is the fast path. That file is the code's catalog hash. Equal hashes return. okm_history and catalog.json stay unread. A difference reads catalog.json once per process. Concurrent connects share that read. Connect does not rebuild the catalog from the schema.

OKM1027

A missing catalog.json is .okm/catalog.json is missing. when catalogDir is .okm. Omitted, the directory in that message is .okm under the process cwd. The fix is Run okm build so catalog.json matches catalog.hash. connect does not rebuild the catalog from the schema.

OKM1027

A hash that does not match the JSON is Catalog hash does not match the build artifact.

OKM1027

UTF-16 catalog.hash is catalog.hash is UTF-16. Save the file as UTF-8.

hash

With no hash, and without Require meta, the drift check is skipped. The floor still runs. Equal catalog hashes return without reading okm_history. The floor still runs. A different hash loads the catalog. The check then reads okm_history.

Ahead by expand migrations, the drift check returns. The client opens when the floor passes.

Any other verdict is OKM1520. The id is the migration id from okm_history.

VerdictMessage
ahead by contractThe database is ahead by contract migration 0002_expand.
behind by expandThe database is behind by expand migration 0003_expand.
behind by contractThe database is behind by contract migration 0002_contract.
behindThe database is behind the app at migration 0001_old.
behind, no idThe database is behind the app.

A failed read of okm_history uses The database is behind the app. A schema catalog hash that differs is this comparison.

connected

A query waits for db.connected. Await it when the check must finish before close().

close(), before the check settles, on a client that opened the pool, rejects connected when the check fails. The message is The client was closed before it connected. Await connected before close(), or do not close it before use.