Skip to main content
All signatures on this page are verified against the current @exulu/backend source. For what each method does and how to structure your initdb script, see Configuration.

Import

ExuluDatabase is a plain object — not a class instance. There is nothing to construct.

ExuluDatabase.init()

Initialises or updates the IMP database schema. Idempotent — safe to call on every boot.
contexts
ExuluContext[]
required
All ExuluContext instances registered in this application. IMP creates the items table (and chunks table when the context has an embedder) for any context whose tables do not yet exist.
litellm
boolean
default:"true"
When true, also calls initLitellmDb() to push the LiteLLM proxy schema to the database at LITELLM_DATABASE_URL. Pass false to skip.
What init() does on every call:
  1. Runs up(db) — creates or alters the ~26 core application tables.
  2. Calls contextDatabases(contexts) — creates missing items and chunks tables for each context.
  3. Inserts the admin role if absent.
  4. Inserts the default role if absent.
  5. Inserts the default admin user (admin@exulu.com) if absent.
  6. Calls generateApiKey("exulu", "api@exulu.com") and logs the result. The key is persisted only if no api@exulu.com user exists (first boot). See persistence semantics.
  7. Optionally calls initLitellmDb().

ExuluDatabase.update()

Alias for init(). Identical behaviour. Use when adding contexts or upgrading an existing installation to make the intent explicit.

ExuluDatabase.api.key.generate()

Creates an API user record and returns the plain-text API key. Calling this function is the only way to obtain the clear-text key — it is never stored in the database in recoverable form.
name
string
required
Human-readable identifier for this API key. Used as the name column on the API user record and as the sanitized postfix in the key string: sk_…/sanitized_name (lowercased, spaces replaced with underscores).
email
string
required
Email address for the API user record. Trimmed and lowercased before use. Used as the lookup key — if a user with this email already exists, the new key is returned but not persisted (see persistence semantics below).
key
string
The generated plain-text API key. Format: sk_{random}_{random}/{sanitized_name}. Example: sk_9x7h3j2k5l8_4m6n1p9q8r/my_app_api.

Key format

The returned key has three parts: The database stores {bcrypt_hash(plain_key)}/{sanitized_name} in the apikey column. The hash uses 12 bcrypt salt rounds. IMP’s authentication middleware extracts the postfix suffix to find the user record before verifying the hash.

Persistence semantics

The function always returns a valid-looking key. Only the key generated when no prior user with that email exists is stored and will authenticate. Keys returned for existing users are discarded and will fail authentication.
The first call with a given email address is the only one that persists the key. If you regenerate a key for an existing email, the new key will not work. To replace a key, delete the user record first and call generate() again.

Example

Generating multiple keys

To provision keys for different services, use different email addresses:

The first-boot key

ExuluDatabase.init() calls generateApiKey("exulu", "api@exulu.com") internally on every run and logs the result:
Only the key logged on the first boot is persisted. Keys logged on subsequent boots are not stored and will not authenticate. Capture the key before log rotation or terminal scrollback clears it:
For a dedicated application key with a stable email, call ExuluDatabase.api.key.generate() explicitly after init() in your initdb script — that key is tied to your email address and will not conflict with the default api@exulu.com entry.

Context table helpers

These methods are called by ExuluDatabase.init() internally via ExuluContext. You rarely need to invoke them directly; they are listed here for completeness and are documented on the ExuluContext API reference page.

Next steps

Configuration

Options for init() / update(), the LiteLLM flag, and the complete initdb example.

Self-hosting — database

The no-migration model, first-boot bootstrap, and database backup strategy.