Glossary

Every term denver uses, defined once. The rest of the documentation assumes these definitions.

The core model

Environment — a directory containing a denver.yml, and the unit denver launches: denver run <env>. An environment is fully described by its denver.yml (plus whatever that file explicitly points at); reading the file tells you everything the environment does. <env> may also be a path directly to a config file, so one directory can hold several variants side by side (denver.debug.yml, denver.release.yml).

denver.yml — the config file describing one environment: which stages run, in what order, and how each is configured. denver’s default format; denver.toml works too. Its schema is documented in Configuration.

Stage — one entry in stages:: a provider type plus its own config section, run in order. The entry is the stage id, and the top-level section of the same name is that stage’s config. A stage id is just a label — the section must always declare provider: <name> explicitly — which is what lets one environment run two uv stages (e.g. uv and uv-zephyr) targeting different venvs.

Provider — the generic engine behind a stage type. denver ships eight: uv, conan, zephyr, docker, download, git, nix and custom. A provider holds no project-specific knowledge; everything specific comes from the denver.yml section it is given. See providers/.

Extension provider — a project’s own Provider subclass, registered via extensions: providers: dirs: instead of being built into denver. Behaves exactly like a built-in provider everywhere else once registered — see “Extension providers” in Configuration.

Step — a stage’s own internal sub-phase, e.g. conan’s prepare/export/install or uv’s ensure-python/ensure-venv/install/activate. Each step prints its own banner line (--verbose only — see Verbose), in whatever order the provider actually does the work; there is deliberately no “step 3 of 7” numbering to keep in sync with the code.

Every stage is announced by a single -- [i/n] stage '<id>' (<provider>) line before its first step — shown at the default verbosity, unlike the finer step banners below it — emitted by denver itself rather than by the provider — so a stage that fails before doing anything (a missing tool, a bad path) has still said which stage it is, and <id> is exactly what --skip takes. Stages report in stages: order whether they run or are skipped, so the trail reads as the pipeline it describes.

Setup provider (kind: setup) — a provider that builds part of the environment in place: creates a venv, installs tools, updates a workspace. uv, conan, zephyr, download, git and nix are setup providers; custom is one unless it declares launcher:.

Wrapper provider (kind: wrapper) — a provider that builds nothing itself and instead relocates the final command somewhere else, e.g. into a container. docker is denver’s wrapper provider; a custom stage with launcher: acts as one too.

Wrapper relocation — what running an environment that stacks a wrapper actually does: denver builds/enters the container and re-invokes itself inside it with --skip <that stage>, so the remaining setup stages build the environment in there rather than on the host. Skipping the wrapper yourself (denver run <env> --skip docker) runs the exact same stack directly on the host.

Configuration

Resolved config — a stage’s config section after every default has been filled in centrally, before any stage runs. This is exactly what --show-config prints, and exactly what a real run uses — the two can never disagree, because a provider’s setup() never computes a default of its own.

Whole-file import: — one denver.yml inheriting another environment’s entire stack as a base, then adding or overriding only what differs. This is how a version-specific environment reuses a shared base without copy-pasting its stages:/docker:/conan:/uv: config.

Section-level import: (also called stacking) — one stage section pulling its content from another environment’s section, without inheriting that environment’s entire stack. An entry may name a specific section (path:section) instead of the same-named one.

Merge rules — how two layers combine: mappings merge key by key recursively; lists append (lower layer’s entries first); two layers setting the same string key to different values is a hard error unless the override is prefixed with !. See Configuration for the details, including the <overwrite> marker.

Interpolation${VAR} / ${VAR:-default} expansion inside denver.yml values, resolved against the environment denver is building (including its own built-ins such as DENVER_ENV_DIR).

Hook — a script sourced (not merely executed) at a fixed point, so its exports become part of the environment everything after it runs in. The hook points are env (once, before any stage), pre-<stage> / post-<stage> (around each stage), and pre-cmd (right before the final command).

scripts: / --scripts <name> — the generic, open-ended one-shot mechanism, distinct from hooks: any stage section may declare scripts: <name>: [...], and denver run <env> --scripts <name> runs every stage’s <name> entries and then exits without running the pipeline. <name> is arbitrary — setup and login are conventions, not built-in flags.

Execution

Fingerprint (or checksum) — the mechanism a stage uses to detect that nothing relevant changed since its last successful run (requirement file contents, recipe content, workspace state, …) and skip its own expensive step. This is what makes a repeat run take seconds instead of minutes. --force bypasses it; --fast skips the build step without even checking.

Dry run--dry-run walks the pipeline for its description instead of its effect: each stage’s commands and file writes are printed (tagged [dry-run <marker>], each marker its own color — see CLI Arguments) rather than performed, and the final command is printed rather than launched. Read-only queries (?) and sourced scripts (.) still run — they are what the printed commands are derived from. A wrapper stage can’t be previewed past its own boundary; see Configuration.

Stage filtering — restricting which stages run: --until <stage> truncates the pipeline after the named stage, --skip <stage> removes individual stages, and a stage’s own disabled: true opts it out by default.

Quiet level-q silences denver’s own output (progress trail, info lines, everything -v/--verbose would add) while keeping each stage’s own build-tool output; -qq silences that too, leaving only the launched command’s own output. Errors always print. See also Verbose.

Verbose-v/--verbose turns on denver’s own diagnostic detail, hidden by default: each stage’s finer sub-step banners, the per-stage/env performance timings (in blue), and the + cmd echo ahead of every command denver runs. -q/-qq always win over it.

State directory — where denver keeps everything it builds for one environment (venv, install trees, fingerprints, logs, performance.jsonl): <env dir>/.denver/<config file stem>/, inside the environment’s own directory and ignoring itself via a .gitignore denver writes there. Keyed on the config file, so two variants in one folder — and two checkouts of one project — never share it.

DENVER_ENV_WORKDIR / DENVER_CACHE_DIR — the environment variables denver itself reads: the exact directory to relocate the state directory above to, and (separately) the shared cache root denver exports for an env to point a tool’s own download cache at. Full explanation in Environment variables.

[!NOTE] Next: Philosophy — the principles these terms were chosen to serve. Or go straight to denver in 30 minutes and put them to use.