ExuluDatabase is an object exported from @exulu/backend that wraps IMP’s database setup routines. You call it from the utils:initdb script in your project — the same script that runs on every backend and worker boot via npm run utils:initdb. Its two initialisation methods are identical in behaviour; update() exists as a semantic alias for init() when you want to make it clear you are adding to an existing schema rather than setting it up from scratch.
For the operations side of the database (backups, the no-migration model, LiteLLM schema, and pgvector), see Self-Hosting — Database. This page documents the programmatic API.
What ExuluDatabase does
Core schema
Creates or updates ~26 core tables (agents, users, roles, sessions, variables, and more) using idempotent
CREATE TABLE IF NOT EXISTS and ALTER TABLE … ADD COLUMN patterns.Default bootstrap
On first run, creates the
admin and default roles and the default admin user (admin@exulu.com). Logs and persists one API key for api@exulu.com.Per-context tables
For each
ExuluContext you pass, creates the context items table and (when an embedder is configured) the chunks table with the correct pgvector column dimensionality.LiteLLM schema
Optionally runs
initLitellmDb() to keep the LiteLLM proxy schema current. Enabled by default; pass litellm: false to skip.API key generation
api.key.generate(name, email) creates an API user record and returns the plain-text key — the only moment it is available in clear text.Idempotent
Safe to call on every boot. Tables and columns that already exist are left untouched; only missing structures are added.
The initdb pattern
The recommended pattern is autils/initdb.ts script in your project that imports your contexts and calls ExuluDatabase.init():
package.json:
First-boot bootstrap
On first boot (before any of the target tables exist),init() creates:
- An
adminrole with full write access to agents, API, workflows, variables, users, evals, and budget management. - A
defaultrole with write on agents and read on everything else. - A default admin user with email
admin@exulu.comand bcrypt-hashed passwordadmin. - One API key for
api@exulu.comwith admin role; the plain-text key is logged to stdout once and never stored again.
generateApiKey("exulu", "api@exulu.com") internally. Subsequent boots call the same function; since the user record already exists (matched by email), the new key is returned but not persisted. Keys logged after the first boot will not authenticate. See API key persistence semantics for the exact behaviour.
Subsequent boots
On every subsequent boot,init() / update() checks each table and column for existence before acting:
- Tables that already exist are checked for missing columns; missing columns are added with
ALTER TABLE. - Tables that do not exist are created.
- Role and user records are inserted only when absent.
- One-time data migrations are gated on column-existence checks and become permanent no-ops after their first successful run.
ExuluDatabase.init() freely in your startup code without worrying about data loss or conflicts.
Next steps
Configuration
init() and update() options, LiteLLM flag, and context table creation details.API reference
Full method signatures,
api.key.generate() return type, and key persistence semantics.