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.
bunx okm init.
├── .env.example
├── .gitattributes
├── .gitignore
├── .okm
│ └── init.json
├── db
│ ├── client.ts
│ └── schema.ts
├── migrations
│ └── .gitkeep
├── okmodel.config.ts
└── package.jsonFiles okm init writes
| File | What it is for |
|---|---|
db/schema.ts | Example users table. t.id(), minPostgres: 15, and a named app schema. |
db/client.ts | The 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.ts | schema is ./db/schema.ts. migrations is ./migrations. database is set only when DATABASE_URL is a non-empty string. |
migrations/.gitkeep | The migrations directory. |
.env.example | DATABASE_URL= with no value. Init does not write .env. |
.gitattributes | Line endings for migration SQL, catalog JSON, and .okm. |
.gitignore | .env and .env.local. |
package.json | Adds the okmodel dependency and db:check, db:plan, db:apply, and db:status. |
.okm/init.json | The 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.
bun run --bun okm check
bun run --bun okm migrate plan init
bun run --bun okm migrate applyokm generate init writes the first migration. That is a different command. The tutorial uses okm push.
| Next | You use it for |
|---|---|
| First migration | Generate the first SQL file, then apply one change. |
| Queries | The rest of the calls on a table. |
| Config | Targets, paths, timeouts, and roles. |
| Safe use | Pin the lockfile, wait before updating, and read provenance. |