Configuration
fabrica reads a single TOML file, layered over built-in defaults and overridable
by the environment. A fully-commented starting point ships as
fabrica.example.toml; copy it, keep only the keys
you change, and validate with fabrica config check.
Resolution order
Sources are merged in the following order; a later source overrides an earlier one key-by-key:
- Built-in defaults (every key has one — a bare config is valid).
/etc/fabrica/fabrica.toml$XDG_CONFIG_HOME/fabrica/fabrica.toml(falls back to$HOME/.config/fabrica/fabrica.toml)--config <path>passed on the command lineFABRICA__*environment variables
Missing files are skipped silently, so the same binary serves a first-run machine and a fully-configured one.
Environment overrides
Environment variables are prefixed FABRICA__ and nest with double
underscores; single underscores inside a key are preserved:
FABRICA__SERVER__PORT=8080 # -> server.port
FABRICA__INSTANCE__DEFAULT_BRANCH=trunk # -> instance.default_branch
FABRICA__LOG__LEVEL=debug # -> log.level
Secret files (*_file)
Any key ending in _file reads its value from that file and takes precedence
over its inline sibling. This keeps secrets out of the config file for
agenix / systemd-creds / Docker secrets:
| Inline key | File key | Contents |
|---|---|---|
auth.secret |
auth.secret_file |
HS256 session-signing key |
mail.password |
mail.password_file |
SMTP password |
A single trailing newline is trimmed from the file. Secrets are never logged,
never appear in error messages, and render as <redacted> in
fabrica config show.
Validation
Validation is strict and fails fast with actionable messages:
- Unknown keys are an error. A typo (
protforport, a misplaced section) aborts the load rather than being ignored. instance.urlmust be a valid URL and must not have a trailing slash.instance.default_branchmust not be empty.storage.data_dirandstorage.repo_dirmust exist or be creatable (they may be created on first run).mail.backend = "smtp"requiresmail.hostandmail.from.
Some conditions are warnings — printed to stderr but non-fatal:
auth.cookie_secure = truewith a non-httpsinstance.url: browsers will drop the session cookie. Use this only for local development.
Sections
Each section maps one-to-one to a [table] in the TOML file. See
fabrica.example.toml for the default value and a comment on every key.
| Section | Purpose |
|---|---|
[instance] |
Identity, canonical URL, default branch, anonymous access. |
[server] |
HTTP bind address/port, proxy trust, body-size and drain limits. |
[ssh] |
SSH bind address/port, host key path, advertised clone endpoint. |
[storage] |
Data and repository directories on disk. |
[database] |
Connection URL (sqlite:/postgres:) and pool size. |
[auth] |
Session/token lifetimes, cookie settings, Argon2id cost, signing key. |
[mail] |
Backend (smtp/stdout/none), sender, SMTP endpoint and encryption. |
[ui] |
Theme, asset/theme directories, diff/highlight limits. |
[git] |
git binary path and pack-transport limits. |
[log] |
Level and format (pretty/json). |
Commands
fabrica config check— validate the effective configuration and exit. Printsconfiguration okand exits0on success; prints the problems and exits1otherwise. Warnings are printed but do not change the exit status.fabrica config show— print the effective, merged configuration with secrets redacted. Add--jsonfor machine-readable output.
Both honour the global --config <path> flag.