Get started

Project structure

The files the tutorial writes, and the files okm init writes.

See the files in the project and what each one is for.

You have followed Installation and First schema, or you have a directory with package.json and a Bun lockfile.

Use the tutorial layout when the files stay flat, the driver is postgres.js, you apply with okm push, and the database can be recreated. Use the okm init layout when the schema and the client live in db/, the SQL files live in migrations/, and the scripts are check, plan, apply, and status.

Tutorial files

The tutorial writes these files in the project directory. schema.ts default-exports the notes schema. okmodel.config.ts is the file okm push reads. db.ts is the client. check.ts waits until the startup check finishes. insert.ts, find.ts, one.ts, count.ts, exists.ts, update.ts, and delete.ts are the calls. find-without-limit.ts and update-without-where.ts are the calls that throw OKM1101 and OKM1102.

okm init

okm init writes starter files. It does not connect. In a directory whose package.json name is notes, with a bun.lock and no driver package, and with no terminal, bunx okm init writes this tree. A Bun project with no driver package selects bun-sql. The tutorial installs postgres.js and imports okmodel/pg/postgresjs.

Terminal
bunx okm init
init.tree
.
├── .env.example
├── .gitattributes
├── .gitignore
├── .okm
│   └── init.json
├── db
│   ├── client.ts
│   └── schema.ts
├── migrations
│   └── .gitkeep
├── okmodel.config.ts
└── package.json

Files okm init writes

FileWhat it is for
db/schema.tsExample users table. t.id(), minPostgres: 15, and a named app schema.
db/client.tsThe client. An empty DATABASE_URL is refused. This run imports okmodel/pg/bun. connect includes limits. The library does not set them unless that object is there. Query limits.
okmodel.config.tsschema is ./db/schema.ts. migrations is ./migrations. database is set only when DATABASE_URL is a non-empty string.
migrations/.gitkeepThe migrations directory.
.env.exampleDATABASE_URL= with no value. Init does not write .env.
.gitattributesLine endings for migration SQL, catalog JSON, and .okm.
.gitignore.env and .env.local.
package.jsonAdds the okmodel dependency and db:check, db:plan, db:apply, and db:status.
.okm/init.jsonThe choices and the hash of each file init wrote.

db/client.ts passes this limits object. find 100 covers find, descendants, and ancestors. include 20 is a to-many include. page 50 is page(). groupBy 500 is a grouped aggregate. max 1000 is the ceiling. .all(reason) reads past them. A limit on the call wins.

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

const users = table("users", {
  id: t.id(),
  email: t.text(),
  createdAt: t.timestamptz(),
});
const app = schema({ minPostgres: 15, tables: [users] });

const url = process.env.DATABASE_URL;
if (url === undefined || url.length === 0) {
  throw new Error("DATABASE_URL is not set");
}

export const db = connect(url, {
  schema: app,
  limits: { find: 100, include: 20, page: 50, groupBy: 500, max: 1000 },
});

The command ends with the next three commands.

init.next
bun run --bun okm check
bun run --bun okm migrate plan init
bun run --bun okm migrate apply

okm generate init writes the first migration. That is a different command. The tutorial uses okm push.

NextYou use it for
First migrationGenerate the first SQL file, then apply one change.
QueriesThe rest of the calls on a table.
ConfigTargets, paths, timeouts, and roles.
Safe usePin the lockfile, wait before updating, and read provenance.