vike
ReferenceSettings files

preferences.toml

Taste and tuning — the two independent log levels, the chart style and the sweep thread bound — the one settings file where nothing is a ceiling and both log levels apply without a restart.

crates/vike-config/src/preferences.rs is the authority for this file. Its header draws two lines. Against config.toml: would a second machine need a different value? — a log level or a chart style would not, they express what the operator likes. Against policy.toml the line is sharper: policy sets the bound, a preference sets the value inside it. settings/preferences.example.toml states the consequence plainly — nothing here is a risk control. A preference may be wrong and cost you a readable screen; it can never place a larger order.

Every key carries the full chain: environment variable, then this file, then the default — with one reservation: vike_config::CONSUMPTION still marks preferences.sweep_threads unconsumed, because crates/vike-backtest/src/harness/sweep.rs's sweep_threads reads VIKE_SWEEP_THREADS itself and none of its callers load settings, so only the variable bites for that one key today.

keyenvironment variabledefaulthot-appliable
log_levelRUST_LOG, then VIKE_LOGDEFAULT_LOG_LEVEL = infoyes
log_file_levelVIKE_LOG_FILE_LEVELDEFAULT_LOG_FILE_LEVEL = traceyes
chart_styleVIKE_STYLEabsent — the GUI's own defaultno
sweep_threadsVIKE_SWEEP_THREADSabsent — min(4, available_parallelism())no

log_level is the console filter, in standard tracing directive syntax (info, warn, or a targeted info,vike_exec=debug). RUST_LOG is checked first, matching vike_log::init, and VIKE_LOG is the Vike-flavoured alias.

log_file_level is the JSON log file's own level, and it is independent of log_level, which filters the console only.

This is the disk knob, and the surprise is that RUST_LOG does not touch it

The file layer defaults to trace and captures the log-to-tracing bridge, so a chatty dependency writes at trace no matter how quiet the terminal looks. The example file carries the measurements: one hour of pmxt_backfill wrote 6.4 GB, and one long range wrote 341 GB and nearly filled the disk hosting a live trading node. Set this to warn for any long backfill or replay run — off silences the file entirely — and still watch the size of config.log_dir. The shipped systemd units all set it to warn. The default is kept at trace in DEFAULT_LOG_FILE_LEVEL deliberately, so that introducing this file changed nothing; the field exists so a deployment can finally turn it down in a file instead of an environment variable.

chart_style is the style vike-desktop opens new chart windows with. Absent means the GUI's own default. It is read only by vike-desktop, so it does nothing on a headless daemon or a recorder box.

sweep_threads bounds the rayon pool a parameter sweep installs. Absent falls back to vike-backtest's own min(4, available_parallelism()), and the example file notes it must not be zero. It is the one key here the file cannot yet set: sweep_threads reads VIKE_SWEEP_THREADS itself and none of its callers load settings, so today only the variable bites.

The two hot keys

crates/vike-tradehub/src/hot_reload.rs classifies every config, preferences and flags 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 exactly preferences.log_level and preferences.log_file_level — a pin, so growing the set is a deliberate diff on that line plus a reasoned table row rather than a drive-by. Every hot row must carry a written reason, checked for length the way vike_config::consumed's gate checks its own; the module calls this the power-granting class carrying its own justification.

A hot write does not apply on the server's connection thread. The accepted write enqueues an apply job and blocks, bounded by HOT_APPLY_DEADLINE, while the daemon's existing periodic summary tick — the same off-fold thread that prints the stdout summary and drives alerting — drains the queue and executes the apply. One thread owns every runtime mutation, so two concurrent writes cannot race an apply and nothing new touches the core fold. Response::SettingsWritten.restart_required is false only when the tick confirmed the apply executed inside the deadline; a timeout, a failed apply, a daemon without the seam wired and a restart-class key all answer true, which is always safe. The one residual the module declares: an apply that lands after the deadline was already reported as restart-required — conservative, never false the other way.

The rate_utilization tombstone

The field is gone and the key is now refused by name rather than ignored, and the story is worth keeping because the example was wrong in the one way that matters. rate_utilization claimed to replace the compiled-in vike_model::rate_limits::DEFAULT_UTILIZATION, and policy.rate.max_utilization clamped it at the end of the load with a warning naming both halves. Nothing read the result. Every pacer takes its target fraction from vike_binance::family::klines::KlineSpec::utilization, and every construction site of that field fills it with the constant. So an operator could set the preference, watch it validate, watch vike-cli config show attribute it to their file, watch the policy ceiling clamp it, read a warning about the clamp, and change nothing at all. There was also a --rate-utilization CLI override that no binary parsed.

Both halves are tombstones now. The concept did not leave the product, only this file: vike_model::rate_limits owns the number and its bounds, and — the part a single float in this struct could never express — per-venue overrides through vike_model::RateLimitConfig. A pacing knob that cannot say 40 % on binance, 20 % on aster is the wrong shape. The field also deliberately never got a VIKE_RATE_UTILIZATION environment name, for a reason that still holds for any future one: a program whose end state is no crate calls env::var except vike-config should not open by minting a new environment variable.

With that field gone there is no policy-bounds-preference clamp left in the loader. crates/vike-config/src/lib.rs's header says so outright, and crates/vike-config/src/load.rs's layered load now ends at the CLI layer, carrying a comment where the clamp call used to sit. The mechanism is not repudiated, only uninstanced — policy sets the bound, a preference sets the value inside it is still the spine of the split, and the first real bound/value pair brings the pass back, ideally with the gate that would have caught this one. vike-cli config show --filter preferences prints which layer won for each key — see the config verb.

On this page