Skip to content

The conf.d merge model

This is the core of PolyForge’s architecture. Everything else is convention; this is mechanism.

mise composes configuration in two independent ways. PolyForge uses both, for different jobs.

1. Fragment merge — .config/mise/conf.d/*.toml

Section titled “1. Fragment merge — .config/mise/conf.d/*.toml”

Every .toml file in conf.d/ is loaded, in alphabetical order. The numeric prefixes are not decoration — they are the load order, and they encode intent:

  • Directory.config/mise/conf.d/
    • 00-settings.toml global behaviour — jobs, auto_install = false
    • 10-core-tools.toml interpreters — python, node, go, rust, java, dart, flutter
    • 20-cli-tools.toml the toolbelt — eza, bat, ripgrep, fd, jq, zoxide, delta, btm
    • 30-package-managers.toml bun, deno, pnpm, uv, zig, cmake, ninja

Settings land first so everything after inherits them. Interpreters before the package managers that depend on them. New categories slot into the gaps — 40-elixir.toml, 25-database-tools.toml — without touching an existing file.

2. Tree merge — up the directory hierarchy

Section titled “2. Tree merge — up the directory hierarchy”

mise walks up from your current directory, collecting configuration as it goes. Because conf.d/ sits at the workspace root, its tools are in scope in every subfolder — Workspace/Go/, Dev/Learn/python/day04-decorators/, everywhere.

A deeper mise.toml then inherits its ancestors’ tasks and environment and overrides only what it names:

polyforge/
├── .config/mise/conf.d/*.toml ← base toolchain, workspace-wide
├── mise.toml ← root orchestration: env, hooks, tasks
└── Workspace/
└── Go/
└── mise.toml ← inherits the above, overrides Go specifics

The obvious design would be one mise.toml that imports fragments. mise 2026.6.x does not support includes or import.

Rather than work around a missing feature with a build step or a generated file, PolyForge uses the two merges mise does guarantee. The result is arguably better than the import version would have been: there is no generated artifact to keep in sync, and adding a language is genuinely a single new file.

Alphabetical order is real order. A fragment named 05-experimental.toml loads before 10-core-tools.toml and can be overridden by it. Name files for where you want them in the sequence.

Later fragments win on conflict. If two fragments declare the same tool, the one that loads later takes precedence. Keep each tool in exactly one fragment.

Scope follows the tree, not the project. A tool is available because of where you are standing, not because a project declared it. If you want a tool available only inside one language area, declare it in that area’s mise.toml, not in conf.d/.

Depth costs nothing. Being ten directories deep inside a project does not change what is available — mise still walks all the way up to the workspace root.

The whole procedure:

  1. Create a fragment in .config/mise/conf.d/, numbered for its category.
  2. Optionally add Workspace/<Lang>/mise.toml for language-specific env or tasks.
  3. Run polyforge install.

Step-by-step in adding a language; the file schema is in the conf.d reference.