Configuration Precedence
Octipus keeps configuration in two stores across two stages. Knowing which one wins when saves a lot of confusion.
.envis bootstrap-only. Read once on first boot, then ignored.- The DB
settingstable is the runtime source of truth. Changed via the web UI, the/settingsAPI, or directly — and it survives restarts. - The vault (encrypted
vaulttable) 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.
The boot sequence
Section titled “The boot sequence”.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 mirrorsthe DB. DB writes hot-reload through the cache.Which keys live where
Section titled “Which keys live where”| Key | Store | Edit via |
|---|---|---|
STORAGE_MODE | .env | re-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 | .env | regenerate with care — see warning below |
JWT_SECRET | .env | regenerate (invalidates sessions) |
SESSION_SECRET | .env | regenerate (invalidates sessions) |
PORT / HOST | .env | edit + restart |
BOOTSTRAP_PROVIDER etc. | .env | first-boot only; no effect once a model is in the DB |
| LLM provider configs | DB model_config | Models page / API |
| Channel tokens | Vault | Channels page |
| Topic → role bindings | DB settings | Models page |
| Persona presets | DB profiles, YAML in personas/ | /persona … slash command |
| Workspace path | DB settings | UI / 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.
Why two stores?
Section titled “Why two stores?”- Storage mode + DB URL must be readable before the DB connection is open. They live in
.env. - Security keys must be available before the vault is unlocked. They live in
.env. - 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.
Rotating the master key
Section titled “Rotating the master key”If you genuinely need to rotate (compromised key, fresh install), the safe procedure is:
- Export every vault entry’s plaintext via the Secrets page.
- Generate a new
MASTER_KEYand put it in.env. - Restart Octipus.
- Re-add every secret via the UI.