Boot files
Code that runs before the server opens.
A boot file is a .ts file at the top level of boot/. It runs once at startup, before the app serves. Use it for anything that must exist before the first request. dirs.boot in config moves the directory elsewhere.
The most common registration is a hook:
import { hook } from 'ohnejs';
hook('server:ready', ({ host, port }) => {
console.log(`accepting connections at http://${host}:${port}`);
});There is nothing to export and nothing to call, and nothing imports the file either. ohne finds it at startup and imports it for you. That import runs the code at its top level, which is all a boot file needs.
When they run
Boot files run right after the layer stack loads: before types regenerate, before the schema sync, and before the port opens. Whatever a boot file registers is in place for everything that follows. If a boot file throws, startup stops before anything serves.
They run under ohne serve api, ohne dev (again on every reload), ohne sync, and before every command of your own. The dashboard server does not run them.
Ordering
Within one boot/ directory:
- Every top-level
.tsfile runs, sorted naturally by name, so2-runs before10-. Each file finishes before the next starts. - Nested files are ignored.
- A
_-prefixed file is a helper. The scan skips it, and the other files can import it. - An
index.tstakes over. When present, it is the only file that runs, and it imports the rest in its own order.
Across layers, the furthest layer boots first. A base layer's registrations are in place when your boot files run, and its hooks fire before yours. Each layer reads its own dirs.boot.
Registering a dialect
A boot file is where a layer adds a new dialect to the database. It registers the implementation:
import { useDialects } from 'ohnejs';
import { PostgresDialect } from '../database/postgres.ts';
useDialects().register('postgres', new PostgresDialect());A second file augments KnownDialects, so config accepts the name:
import type {} from 'ohnejs';
declare module 'ohnejs' {
interface KnownDialects {
postgres: true;
}
}Keep the two apart. ohne imports every layer file that augments ohnejs into the app's types, so a driver import there would pull the driver's types into every app. Other dialects covers what a dialect does.
Registering an existing name overrides it, so a dialect from a closer layer wins. This is the same furthest-first order that lets your app override a base layer.