> ## Documentation Index
> Fetch the complete documentation index at: https://docs.intelligence-management-platform.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Introduction

> ExuluDatabase is the programmatic API for IMP's idempotent database initialisation — it creates core tables, bootstraps default roles and admin credentials, provisions per-context tables, and generates API keys.

`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.

```typescript theme={null}
import { ExuluDatabase } from "@exulu/backend";

await ExuluDatabase.init({ contexts, litellm? });
await ExuluDatabase.update({ contexts, litellm? });

const { key } = await ExuluDatabase.api.key.generate(name, email);
```

<Note>
  For the operations side of the database (backups, the no-migration model, LiteLLM schema, and pgvector), see [Self-Hosting — Database](/self-hosting/database). This page documents the programmatic API.
</Note>

## What ExuluDatabase does

<CardGroup cols={2}>
  <Card title="Core schema" icon="table">
    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.
  </Card>

  <Card title="Default bootstrap" icon="user">
    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`.
  </Card>

  <Card title="Per-context tables" icon="layers">
    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.
  </Card>

  <Card title="LiteLLM schema" icon="braces">
    Optionally runs `initLitellmDb()` to keep the LiteLLM proxy schema current. Enabled by default; pass `litellm: false` to skip.
  </Card>

  <Card title="API key generation" icon="key">
    `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.
  </Card>

  <Card title="Idempotent" icon="rotate">
    Safe to call on every boot. Tables and columns that already exist are left untouched; only missing structures are added.
  </Card>
</CardGroup>

## The initdb pattern

The recommended pattern is a `utils/initdb.ts` script in your project that imports your contexts and calls `ExuluDatabase.init()`:

```typescript theme={null}
// utils/initdb.ts
import { ExuluDatabase } from "@exulu/backend";
import { docsContext, supportContext } from "../src/contexts";

async function main() {
  await ExuluDatabase.init({
    contexts: [docsContext, supportContext],
  });

  const { key } = await ExuluDatabase.api.key.generate(
    "my-app",
    "api@my-app.com",
  );
  console.log("API key:", key); // Store this securely — never printed again
}

main().catch((err) => {
  console.error(err);
  process.exit(1);
});
```

Add it to `package.json`:

```json theme={null}
{
  "scripts": {
    "utils:initdb": "tsx utils/initdb.ts"
  }
}
```

Run before first launch and after adding new contexts:

```bash theme={null}
npm run utils:initdb
```

## First-boot bootstrap

On first boot (before any of the target tables exist), `init()` creates:

* An `admin` role with full write access to agents, API, workflows, variables, users, evals, and budget management.
* A `default` role with write on agents and read on everything else.
* A default admin user with email `admin@exulu.com` and bcrypt-hashed password `admin`.
* One API key for `api@exulu.com` with admin role; the plain-text key is logged to stdout once and never stored again.

<Warning>
  Change the default admin password immediately after first login. The default credential (`admin@exulu.com` / `admin`) is documented publicly. See [Self-Hosting — Database](/self-hosting/database) for the first-boot warning and recovery instructions.
</Warning>

The first-boot API key is generated by calling `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](/developers/core/exulu-database/api-reference#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.

This means you can call `ExuluDatabase.init()` freely in your startup code without worrying about data loss or conflicts.

## Next steps

<CardGroup cols={2}>
  <Card title="Configuration" icon="settings" href="/developers/core/exulu-database/configuration">
    `init()` and `update()` options, LiteLLM flag, and context table creation details.
  </Card>

  <Card title="API reference" icon="code" href="/developers/core/exulu-database/api-reference">
    Full method signatures, `api.key.generate()` return type, and key persistence semantics.
  </Card>
</CardGroup>
