Configuration

What forgedb.toml is, how it is discovered, the precedence rules, and the binding-time tier model that governs every knob.

ForgeDB reads one project config file, forgedb.toml, at generate time. It holds schema-blind knobs: deployment and behavior settings that are not part of your .forge schema. The schema describes your data shape; forgedb.toml describes how the generated code and the running process behave.

Config is schema-blind

Nothing in forgedb.toml is per-model or field-aware. If a setting depended on a specific model or field, it would be a .forge directive, not a config key. Two apps with entirely different schemas could share the same forgedb.toml verbatim.

Discovery#

A config is found by walking up from the schema, not from where you are standing. ForgeDB takes the nearest forgedb.toml at or above the schema's directory; with none anywhere, built-in defaults apply silently.

forgedb generate all                              # nearest config at or above ./schema.forge
forgedb generate all --schema apps/api/schema.forge   # nearest config at or above apps/api/
forgedb generate all -c prod.toml                 # explicit path (also --config)

Starting at the schema is what lets one config govern several apps, and it is why cd never changes the answer: which config applies is a fact about the tree, not about the invocation.

The walk stops at the first of a repository root, your home directory, or the filesystem root — so a stray ~/forgedb.toml cannot quietly capture every project on the machine.

An explicit -c/--config path is an outright override of the knobs: no walk, and a path that is missing or contains invalid TOML is a hard error. A missing forgedb.toml is not (defaults apply). It does not override which project a schema belongs to — see [project].

Relative paths resolve against the schema

A relative output directory is resolved against the schema's directory, not the config's — the built-in generated default included. Under one shared root config, output = "generated" therefore means apps/api/generated and apps/web/generated — a per-app pattern, rather than one directory both apps overwrite each other in. An explicit --output flag is the invocation's own word and is used verbatim.

Unknown keys are errors#

An unrecognized table, or an unrecognized key inside a known table, fails with the line it appears on. This is deliberately not forward-compatible: a knob an older CLI does not know would otherwise read as applied and silently not be, so fsync = "never" would stay always and you would find out from the generated bytes.

error: forgedb.toml:
TOML parse error at line 4, column 2
  |
4 | [projekt]
  |  ^^^^^^^
unknown field `projekt`, expected one of `project`, `generate`, `tenant`, `auth`, `runtime`, `storage`, `transaction`, `server`, `wasm`, `placement`

Precedence#

For any setting, the highest-priority source wins:

  1. An explicit CLI flag (--output, --schema, …)
  2. The value in the loaded forgedb.toml
  3. The built-in default

Binding-time tiers#

Every runtime/storage knob binds at one of three times. The tier tells you when a change takes effect and how baked-in it is.

TierNameMechanismWhen it binds
AGenerate-time specializationCode is emitted or omitted (e.g. the replication broker, the auto-compaction trigger). The compiler optimizes around code that is not there.forgedb generate
BBaked constSame code, a tailored number baked as a const (e.g. checkpoint interval, cascade depth, the fsync policy value).forgedb generate
CProcess-start envRead once at process start from a FORGEDB_* environment variable (host, port, data dir, JWT settings).Server launch

Tiers A and B bake into database.rs at forgedb generate — change them and regenerate. Tier C is read fresh at each process start, so you change it per deployment without regenerating. The [runtime] and [storage] tables are Tiers A/B; the [auth] table bridges to Tier-C FORGEDB_* env at runtime (see tenant & auth).

fsync is Tier B today

[storage].fsync = "never" bakes the FsyncPolicy value as a const, but the substrate still matches it per-write at runtime — so the barrier syscall is still present in the binary (a dead, value-known branch), not removed. True Tier-A elimination of the barrier is a documented follow-up. See [storage].

The tables#

These are all ten tables forgedb.toml accepts. Any other is an error, so this list is also the complete vocabulary.

TablePurposePage
[project]Project id, isolation, and how derived names are built.[generate] & [project]
[generate]Output dir and which targets to emit. A schema names itself — there is no schema key.[generate] & [project]
[runtime]Replication, changefeed capacity, cascade depth (Tier A/B).[runtime]
[storage]fsync policy, WAL checkpoint, compaction (Tier A/B).[storage]
[transaction]Optimistic-concurrency retry knobs (Tier B).
[server]Generated REST list-page limits and the /metrics endpoint (Tier A/B).
[wasm]Browser read-replica auto-commit debounce and frame ceiling (Tier B).
[tenant]The per-tenant data root.[tenant] & [auth]
[auth]Verify-only JWT tenant guard settings (bridges to FORGEDB_*).[tenant] & [auth]
[placement]Where an already-generated artifact lands. Changes no generated byte.[placement]
[toolchain]Where the interpreter a non-Rust migration transform runs on lives, and which version will do. Location and version only — the language is derived from [generate].targets.Migrations

Defaults are byte-identical#

Generated database.rs from an empty [runtime]/[storage] config is byte-identical to the fully-defaulted output, with one deliberate exception: [runtime].replication defaults to off. An unused durable replication broker would pay a second F_FULLFSYNC barrier per write for nothing, so it is omitted unless you opt in. See [runtime].

Search documentation

Find pages across the ForgeDB docs