vike
ReferenceSettings files

Settings files

Four TOML files in one directory, split by who is allowed to change a value and from where, with the precedence order and the compiler-enforced exception that makes a ceiling a ceiling.

Every setting the typed settings model reads from a file lives in <project>/settings/, in four TOML files. crates/vike-config/src/lib.rs is the typed model and the layered loader, and its header states the split the four files exist to draw: by authority, not by subsystem — one type per level of who may change a value and from where.

One other file carries settings-shaped values, and no live mount starts without it: a run profile, named by --profile or VIKE_RUN_PROFILE and conventionally kept in <project>/user_data/profiles/ — a sibling of settings/, never inside it. Its [risk] table deserializes into crates/vike-exec/src/risk_profile.rs's ProfileRisk and is threaded verbatim into every venue mount through vike_run::NodeConfig::risk_profile, whose neighbouring policy field spells the split: a run profile is per-run and operator-owned, a policy per-machine and admin-owned. crates/vike-mount/src/arming.rs's require_live_risk_budget refuses a live mount whose max_notional_per_order and max_total_exposure no profile supplied — today the [risk] table is the only source that reaches the risk gate, so the same-named notional ceiling in the table below is a second enforcement point at the order surfaces rather than a substitute for it.

filetypeholdswho writes itoverridable by
policy.tomlPolicyhard ceilings — leverage, order notional, market-slippage band, halt admission, per-venue armingorg/adminfile only
config.tomlConfigdeployment — store paths, log dir, listen addressesdeploymentfile, env, CLI
preferences.tomlPreferencestaste and tuning — log levels, chart style, and a sweep-thread bound only VIKE_SWEEP_THREADS sets todayuserfile, env, CLI
flags.tomlFlagstoggles — reconcile, poly exec, control surfaces, recordersoperatorfile, env, CLI

One precedence order applies to all of them, written out in crates/vike-config/src/layers.rs: code defaults → <project>/settings/*.toml → env → CLI. Nothing runs after that layer today — crates/vike-config/src/lib.rs's header records that there is currently no policy-bounds-preference clamp, the mechanism still being the taxonomy's spine but having no instance since the rate_utilization tombstone. What differs per type is not the order but which layers exist, and layers.rs says that table is enforced by the type system rather than by a comment.

The one type with fewer layers

Policy implements neither EnvOverride nor CliOverride, and has no from_env, apply_env or apply_cli inherent method either — so settings.policy.apply_env(&env) is a compile error, not a review comment. Both traits are sealed behind a crate-private supertrait, so a downstream crate cannot bolt an impl on from outside. The argument in that module's header is short: a ceiling you can override with an environment variable is not a ceiling, and the failure mode is silent — a stale systemd unit or an inherited shell raises the limit with no file changed, no diff, no review, and a run that looks completely normal.

There is no fifth override layer

A <project>/vike.toml override layer sat between the settings directory and the environment and is removed. crates/vike-config/src/removed.rs explains why a present one is a startup refusal rather than something ignored: the file was genuinely wired for the hour between the change that wired it and the change that removed the layer, so an operator may have one on disk that took effect. Ignoring it would make their belief silently false. REMOVED_PROJECT_FILE and removed_project_file_message own the message, and a path that cannot be probed refuses too — saying so, rather than claiming the file is there.

What the loader refuses to be quiet about

Unknown keys are rejected by name: every file struct carries deny_unknown_fields, because a typo'd setting that silently does nothing is worse than an error. The crate header states the one limit of that mechanism — it governs a struct's field names, and serde treats a map's keys as data. Policy::venues and PolicyPatch::accounts — the [accounts] table — are the model's maps, so both have their venue ids checked by hand against vike_model::VENUES in Policy::apply, an unknown one refused with the roster in the message, and an account label checked against vike_model::account_keys::AccountLabel::parse.

Every failure names the file and the key. crates/vike-config/src/error.rs sets the bar explicitly: "invalid config" is useless to the person holding the file, while "policy.toml: market_slippage = 0.9 exceeds the allowed maximum 0.05" names the file to open, the value rejected and the bound it broke. Env and CLI failures name the variable or flag instead, because there is no file to open.

A missing file is not an error. A layer with no file contributes nothing and the layer below stands; only a file that exists and cannot be read or parsed fails the load.

Nothing here resolves a directory

The loader is a pure function of its arguments: the settings directory is a parameter, and so is the env map. crates/vike-config/src/load.rs states that this crate never walks, never expands ~ and never reads a platform variable — vike_model::state_path::project_settings_dir_from owns the walk and the binary performs it. That is the workspace rule that libraries take configuration as parameters and only binaries touch the process environment.

Finding out what actually applied

vike-cli config show prints every setting, its effective value and the layer that set it — see the config verb. Provenance is measured, never inferred: crates/vike-config/src/provenance.rs decides an origin by key presence in a parsed layer, not by diffing effective values against defaults, because a policy.toml that sets max_leverage = 1.0 — the same number as the code default — is a file that was read and did configure that key. The precedence header the command prints is rendered from the PRECEDENCE table itself, so it cannot name a layer no binary applies.

A daemon does not wait to be asked. crates/vike-config/src/boot.rs renders the settings directory, one line per file (present or absent, with its key count), the resolved settings, and the credential store's presence — every policy.* row always, plus every row some layer actually configured. Its header carries the incident that motivated it: on one production box the project-root walk answered with an unrelated directory, so the daemon loaded no policy, no config and no credentials, and every venue silently dropped to paper with no error.

Editing, and when an edit takes effect

crates/vike-config/src/write.rs is the write half: it sets one key in one file, preserving the operator's comments and the formatting of every untouched line, validates the would-be text through the same parse-and-apply the loader runs before a byte lands on disk, and writes atomically. crates/vike-tradehub/src/hot_reload.rs classifies each key as hot-safe or restart-required, exhaustively against vike_config::provenance::setting_keys, and its the_hot_set_is_exactly_the_two_log_levels test pins the hot set to preferences.log_level and preferences.log_file_level. policy.toml is never hot by construction — classify answers restart-required for that file before the table is consulted.

Two more pages sit beside these four: the alert rule file alerts.json, which is program-written state rather than a settings file, and the environment variable reference.

On this page