createApp
Every option of createApp and every member of the app object it returns.
import { createApp } from 'locosdk/server'
const app = createApp({ schema, app: config.app, pages: { '/*': index } })
app.serve()
How to use it: Server: hooks, routes, crons.
Options#
| option | default | what |
|---|---|---|
schema | required | the defineSchema(...) of schema.ts |
app | none | the identity of loco.config.ts: names the mails, serves the logo at /api/_/logo |
dir | 'data' | the data folder: <dir>/app.db, <dir>/storage/, <dir>/backups/ |
migrations | [] | { file, up(m) } items, run once each before the schema sync, in file order |
pages | {} | Bun.serve routes of HTML imports, { '/*': index }. /api/* never falls through to a page |
meta | local values | { appName, appURL, senderName, senderAddress }: the {APP_NAME} and {APP_URL} of mails, the sender, the public URL of the MCP server |
mail | sending throws | a transport: smtpTransport(config), or memoryTransport() in tests |
dev | NODE_ENV !== 'production' | hot reload on the pages, no cap on live codes |
rateLimits | *:auth 5 per 3 s | PocketBase's rate limit rules: { label, maxRequests, duration }. A list given here replaces the default, so name *:auth again |
storage | diskStorage('<dir>/storage') | where file fields live: diskStorage(path) or s3Storage(config) |
backups | no cron, keep all, on disk | { cron, maxKeep, storage }, storage is 'disk' or an S3 config |
trustedProxy | { headers: [], useLeftmostIP: false } | the headers that carry the real client IP |
restart | () => process.exit(0) | how the process comes back after a restore |
mcp | off | the app as an MCP server at /mcp: The MCP server |
The app object#
| member | what |
|---|---|
schema | the live schema, after the sync |
db | the bun:sqlite database. app.db.query(sql).all(...params), every value bound. No rules |
records | the trusted records service: list, getOne, getFirst, create, update, delete, transaction, batch. No rules, full validation, after success hooks fire |
mail.send(message) | send through the transport and the onMailerSend chain |
meta | the resolved meta |
route(method, path, handler, ...middlewares) | a custom route: Hooks |
on* | the hooks: Hooks |
cron(name, spec, fn) | a schedule, UTC, five fields or @hourly @daily @weekly @monthly @yearly |
dispatch(request, { auth, body, context }) | an internal request through the router: the route's middlewares and hooks run. What MCP tools call |
backups | create(name?), list(), restore(key), active |
storage | the file storage |
serve({ port? }) | listen on port, else PORT, else 8090. Port 0 picks a free one. Returns Bun's Server |
close() | stop the server and the crons, close the database |
Under bun --hot, a second createApp on the same dir retires the first: its crons stop and its database closes. Bun keeps the socket.
Boot, in order#
- Retire an earlier app on the same
dir(a hot reload). - Open
<dir>/app.db(WAL, foreign keys on, a 10 s busy timeout). - Run the migrations not yet applied, then sync the schema: additive changes apply, a destructive one stops the boot with every problem listed (Schema as code). The sync also checks each auth collection's options and mints a token secret where one is missing.
- Mount the routes: records, auth, files,
/api/health, backups, the changelog, the user copy, MCP when it is on, the logo. - Start the crons: the built in hourly cleanup, and the backup cron when
backups.cronis set.