Skip to content

Configuration Precedence

Octipus keeps configuration in two stores across two stages. Knowing which one wins when saves a lot of confusion.

  • .env is bootstrap-only. Read once on first boot, then ignored.
  • The DB settings table is the runtime source of truth. Changed via the web UI, the /settings API, or directly — and it survives restarts.
  • The vault (encrypted vault table) holds secrets, referenced by name from settings.
  • Hot-reload picks up DB changes without a restart wherever the consuming module subscribes — most LLM/router settings, though not all.
.env file (and process env)
│ read by src/config/bootstrap-loader.ts
Bootstrap config in memory
STORAGE_MODE, DATABASE_URL, REDIS_URL,
MASTER_KEY, JWT_SECRET, SESSION_SECRET,
PORT, HOST
DB initialized + migrations run
First boot only:
migrateEnvToDb ─► populates DB `settings` from .env
bootstrapDefaultModel ─► seeds model_config from BOOTSTRAP_PROVIDER + key
Settings service warms its cache from the DB
Runtime: every getConfig() call reads the in-memory cache, which mirrors
the DB. DB writes hot-reload through the cache.
KeyStoreEdit via
STORAGE_MODE.envre-run bun run setup and pick
DATABASE_URL.env.env directly (external mode only)
REDIS_URL.env.env directly (external mode only)
DATA_DIR.env.env directly (embedded mode only)
MASTER_KEY.envregenerate with care — see warning below
JWT_SECRET.envregenerate (invalidates sessions)
SESSION_SECRET.envregenerate (invalidates sessions)
PORT / HOST.envedit + restart
BOOTSTRAP_PROVIDER etc..envfirst-boot only; no effect once a model is in the DB
LLM provider configsDB model_configModels page / API
Channel tokensVaultChannels page
Topic → role bindingsDB settingsModels page
Persona presetsDB profiles, YAML in personas//persona … slash command
Workspace pathDB settingsUI / API

”I edited my .env but nothing changed”

Section titled “”I edited my .env but nothing changed””

That’s expected for any field tracked in settings. After first boot, the DB wins. To force a re-seed from .env, delete the _system.envMigrated row in the settings table and restart — the migration runs again and overwrites the DB values with the current .env.

For bootstrap-only fields (STORAGE_MODE, DATABASE_URL, MASTER_KEY, …), .env is the source of truth — but you must restart for changes to take effect, since they’re read at boot time.

  1. Storage mode + DB URL must be readable before the DB connection is open. They live in .env.
  2. Security keys must be available before the vault is unlocked. They live in .env.
  3. Everything else benefits from web-UI editability, audit trails, and multi-user scoping. It lives in the DB.

The split is annoying exactly once. octi doctor tells you what’s missing from each side.

If you genuinely need to rotate (compromised key, fresh install), the safe procedure is:

  1. Export every vault entry’s plaintext via the Secrets page.
  2. Generate a new MASTER_KEY and put it in .env.
  3. Restart Octipus.
  4. Re-add every secret via the UI.