Tools & Backends
Install & Activate got mise onto your PATH. Now
let’s pin some tools. This page is about the [tools] table: how to put versions
in it, where the binaries actually come from (the backend registry), and how
to lock it all down so your teammates and CI get byte-identical installs.
use vs install vs exec
Section titled “use vs install vs exec”Three commands, three jobs:
mise use node@22 # install + write it into the nearest mise.tomlmise install # install everything the config already declares (no edit)mise exec -- node -v # run a one-off in a tool's env (mise x for short)| Command | Edits config? | Installs? | When |
|---|---|---|---|
mise use <tool>@<v> | yes (nearest mise.toml) | yes | adopt a tool into a project |
mise install [tool] | no | yes | hydrate a cloned repo / CI |
mise exec -- <cmd> | no | yes (if missing) | ad-hoc, scripts, cron |
mise exec node@22 -- node build.js # pin the version just for this commandmise x python@3.13 -- python -V # x is the aliasGlobal vs local
Section titled “Global vs local”mise use writes to the nearest mise.toml, walking up from your cwd. Two
flags steer where it lands:
mise use node@22 # → ./mise.toml (project-local)mise use -g node@22 # → ~/.config/mise/config.toml (global default)mise use --env local node@22 # → ./mise.local.toml (gitignored, your machine only)mise use --pin node@22 # write the resolved EXACT version, not "22"mise use --remove node # drop a tool from the configVersion specifiers
Section titled “Version specifiers”The right-hand side of a tool entry is more expressive than a plain version string:
| Specifier | Example | Meaning |
|---|---|---|
| exact | "20.11.0" | that version, nothing else |
| fuzzy | "20", "3.12" | latest matching that prefix |
latest | "latest" | newest stable release |
lts | "lts" | newest long-term-support release |
prefix: | "prefix:1.20" | latest within the prefix (explicit form) |
ref: | "ref:main" | build from a git ref / tag / commit |
path: | "path:/opt/node" | use a binary already on disk |
sub-N: | "sub-2:lts" | N releases behind the resolved target |
[tools]node = "22" # fuzzy: newest 22.xpython = "3.13.1" # exactgo = "latest" # newest stableruby = "lts"The [tools] table
Section titled “The [tools] table”The simple forms cover most of life:
[tools]node = "22" # single versionpython = ["3.13", "3.12"] # array — first entry is the default on PATH"npm:prettier" = "latest" # backend-prefixed key — quote itFor tools that need extra setup, use the table form:
[tools]node = { version = "22", postinstall = "corepack enable" }ripgrep = { version = "latest", os = ["linux", "macos"] }my-cli = { version = "1.2", depends = ["node"] }| Key | What it does |
|---|---|
version | the version specifier |
postinstall | shell command run after install (gets MISE_TOOL_NAME / MISE_TOOL_VERSION) |
os | restrict install to these OSes, e.g. ["linux", "macos"] |
depends | install these tools first |
install_env | env vars set during the install |
A polyglot project
Section titled “A polyglot project”Here’s a realistic mise.toml pinning a full backend stack — Node, Python, Go,
and a CLI tool from a language backend:
[tools]node = { version = "22", postinstall = "corepack enable" } # gives you pnpm/yarnpython = "3.13"go = "1.23""npm:typescript" = "5.6" # tsc, from the npm backendripgrep = "latest" # from the registry (aqua)mise install # one command, the whole toolchainBackends & the registry
Section titled “Backends & the registry”When you write node = "22", mise looks up the short name node in its
registry, which maps it to a backend — the actual installation mechanism.
You can see every mapping with mise registry.
flowchart TD
name["node = 22 — short name in mise.toml"] --> reg{"mise registry<br/>lookup"}
reg -->|"preferred"| aqua["aqua:owner/repo<br/>verified downloads, no plugins, Windows"]
reg -->|"fallback"| gh["github: / gitlab:<br/>release assets"]
reg -->|"needs a toolchain"| lang["language backend<br/>cargo: npm: pipx: go: gem: dotnet:"]
aqua --> bin["installed under ~/.local/share/mise"]
gh --> bin
lang --> bin
You can also skip the registry and address a backend directly:
[tools]"aqua:BurntSushi/ripgrep" = "latest""github:cli/cli" = "2.55""cargo:tokei" = "latest""npm:prettier" = "3.3""pipx:ruff" = "latest""go:github.com/air-verse/air" = "latest"The 2026 preference order — and why
Section titled “The 2026 preference order — and why”mise picks backends in this order, and it’s a supply-chain decision, not just ergonomics:
- aqua — the default in 2026. Downloads pre-built release binaries with checksum + signature verification, needs no plugins, and works on Windows. This is the one you want.
- github / gitlab — pull release assets straight from a repo when there’s no aqua entry.
- language backends —
cargonpmpipxgogemdotnet. Great coverage, but they require the relevant toolchain to be installed first and build/fetch from package registries.
Legacy / avoid:
- ubi — deprecated, folded into
github. - asdf — legacy; no longer accepted for new registry entries.
- vfox — not accepted for new entries (but it’s the default backend on Windows).
mise settings add disable_backends asdf # opt out of a backend entirelyThe lockfile: mise.lock
Section titled “The lockfile: mise.lock”Versions like "22" are fuzzy — mise install today and next month can resolve
to different patch releases. The lockfile pins the resolved version, the
checksum, and the per-platform download URL so installs are reproducible.
It’s stable in 2026 — no experimental flag. Enable it once:
[settings]lockfile = true # or set MISE_LOCKFILE=1The lockfile is not created automatically. Generate or refresh it with any install/use operation, or explicitly:
mise lock # resolve current config → mise.lockmise install # also updates mise.lock when lockfile = trueThe file mirrors its config’s basename: mise.toml → mise.lock,
mise.local.toml → mise.local.lock.
Strict installs
Section titled “Strict installs”In CI and Docker, fail loudly if the lockfile can’t satisfy the current platform:
mise install --locked # error if no resolved URL for this platform[settings]locked = true # make --locked the defaultMulti-platform
Section titled “Multi-platform”If your team is on macOS but CI is Linux (and maybe arm64), record entries for every platform up front so nobody hits an “unresolved URL” wall:
mise lock --platform linux-x64,macos-arm64Listing, outdated & upgrading
Section titled “Listing, outdated & upgrading”mise ls # installed tools (versions, source config)mise ls --current # just what's active here (-c)mise ls --outdated # installed vs latest availablemise ls-remote node # every installable version of a toolmise outdated # report tools with newer versionsmise outdated --bump # report newest, ignoring your current specupgrade vs upgrade --bump
Section titled “upgrade vs upgrade --bump”This distinction trips people up:
mise upgrade # upgrade WITHIN your spec — "22" → newest 22.x; no config editmise upgrade --bump # jump to the newest major/minor AND rewrite mise.tomlmise upgrade node --dry-run| Command | Crosses your version spec? | Edits mise.toml? |
|---|---|---|
mise upgrade | no (stays within "22") | no |
mise upgrade --bump | yes (e.g. "22" → "24") | yes |
Supply-chain: --minimum-release-age
Section titled “Supply-chain: --minimum-release-age”Brand-new releases are where supply-chain attacks land first. Tell mise to ignore releases younger than a cooling-off window:
mise use node@22 --minimum-release-age "7d"mise install --minimum-release-age "30d"It’s accepted on use, install, ls-remote, and upgrade, so a freshly
published (and possibly compromised) version won’t get pulled into your stack
until it’s had time to be scrutinised.
Next: your tools are pinned and locked. Now give the project its environment — vars, dotenv files, and secrets — in Environments & Secrets.