Version requests and version files
A version request is the value you give a tool in mise.toml, such as "24" in node = "24". mise resolves each request to a concrete version when it runs; record the resolved versions in a lockfile when everyone must get the same build.
[tools]
node = "24" # a 24.x release
python = "3.14.8" # exactly 3.14.8
ripgrep = "latest" # the release the backend calls latestRequest syntax
| Request | Example | Selects |
|---|---|---|
| Exact version | "24.11.1" | That release. |
| Prefix | "24", "3.14" | A release that starts with the prefix. If a release is named exactly the prefix, that release is chosen. |
latest | "latest" | The release the tool's backend considers newest. |
| Alias | "lts", "project-lts" | The request an alias stands for, such as Node.js lts (24) or a tool alias. |
prefix: | "prefix:1.20" | A release that starts with the prefix, even when a release has exactly that name. |
ref:, tag:, branch:, rev: | "ref:main" | A build from a version-control reference, on backends that build from source. |
path: | "path:/opt/homebrew/opt/node@24" | An existing directory, used as the installation. |
system | "system" | No mise installation. mise adds nothing to PATH for the tool, so the copy already on PATH runs. |
sub- | "sub-1:latest" | The result of subtracting from another request's resolved version. |
A prefix matches at separators: 1.2 matches 1.2.3 and 1.2+build, but not 1.20. Prefixes and latest skip prereleases such as 1.0.0-rc1 unless you request one exactly or set the prerelease tool option.
The same requests work on the command line (mise use node@24, mise exec go@prefix:1.20 -- go version) and in .tool-versions. mise does not accept npm-style ranges such as ^24 or >=20 outside package.json: it warns and then treats the range as a literal version, which fails to install.
mise use node without a version writes latest. mise install node and mise exec node use the version the config selects, or latest when no config declares the tool.
Prefix, reference, path, and subtraction requests
prefix:<PREFIX> exists for tools that publish a release named like a prefix. Go releases before 1.21 were named 1.20, then 1.20.1, so go = "1.20" selects the 1.20 release itself. go = "prefix:1.20" selects the newest 1.20.x release instead.
ref:<REF> builds from a branch, tag, or commit. tag:, branch:, and rev: name the kind of reference explicitly. Support depends on the backend: npm packages from Git accept all four, cargo packages from Git accept tag:, branch:, and rev: but not ref:, spm packages accept ref: and rev:, and plugins accept the references they implement. The Python and Erlang core tools do not build from references.
path:<PATH> uses a directory you built or installed elsewhere, such as a Homebrew keg (path:/opt/homebrew/opt/node@24). ~/ expands to your home directory, and a relative path resolves from the declaring config's config root, or from the current directory on the command line. On Windows, both separators work and mise stores the forward-slash form. In TOML, a backslash starts an escape inside a double-quoted string, so write a Windows path as a literal string ({ path = 'C:\tools\node' }) or double the backslashes ("C:\\tools\\node"). "C:\tools\node" is not rejected: TOML reads \t as a tab, so the path silently changes. On Windows, mise rejects a path that contains a cmd.exe metacharacter (& | < > ^ %), because the path is passed to plugins that build shell commands with it.
sub-<PARTIAL>:<REQUEST> resolves REQUEST, subtracts PARTIAL from the matching components of the result, and resolves what remains as a prefix. sub-2:lts turns Node.js 24 into 22, and sub-0.1:latest turns Python 3.14.8 into a request for 3.13. This is arithmetic on version numbers, not a request for the Nth previous release.
In mise.toml, a table can name the request kind instead of a prefix:
[tools]
go = { prefix = "1.20" }
"npm:github:owner/repo" = { ref = "main" }
node = { path = "/opt/homebrew/opt/node@24" }How a request resolves
mise resolves a request in this order:
- If a lockfile has an entry for the request, mise uses the locked version.
- Aliases expand, so
ltsbecomes24for Node.js. - If an installed version matches the request, mise uses it. A newly published release does not change your environment until you install or upgrade.
- Otherwise mise asks the tool's backend for its versions and picks a match.
Each backend decides what latest means. The github backend, for example, uses the release GitHub marks as Latest, and most backends leave out prereleases. Do not assume latest is the highest semantic version, or that a tool's versions follow semver at all: tools use dates, channels such as nightly, and names such as lts-jod.
mise install node@24 resolves its argument against available releases, so it installs the newest 24.x even when an older 24.x is installed. Other commands, such as mise use node@24 and mise exec node@24, reuse an installed match. A latest request on the command line, such as mise exec node@latest -- node --version, always checks for the newest release.
To see what a request resolves to:
mise ls --current node # the version this directory uses
mise latest --installed node@24 # the installed version that matches
mise latest node@24 # the newest available match
mise outdated # configured tools with newer matchesTo move a project to newer releases, see Upgrade tools. Setting MISE_NODE_VERSION=22 (or MISE_<TOOL>_VERSION for any tool) overrides every config file for the commands that see it; see MISE_* variables.
Version ordering
Most backends list versions in the order their source returns them, and mise picks the last match in that order. For aqua, github, gitlab, forgejo, and http tools that publish releases out of order, such as a 1.x backport after 2.0, set version_order = "semver" so that latest, prefixes, and mise ls-remote use semantic version precedence:
[tools]
"github:owner/tool" = { version = "latest", version_order = "semver" }Versions that are not valid semver, such as nightly, keep their source order ahead of the semantic versions and still match exactly. Build metadata does not affect precedence. For latest, a release the backend marks as latest, such as GitHub's Latest release, still wins unless it has no asset for this tool, which happens in repositories that release several products.
Registry entries set version_order for their tools, so a shorthand such as ripgrep may already use semver ordering. Set version_order = "source" to restore the backend's order. The packslip backend always orders by semver.
Multiple versions of a tool
A tool can request several versions. mise installs all of them, and the first one provides the unversioned command:
[tools]
python = ["3.14", "3.13"]mise exec -- python --version # 3.14.x
mise exec -- python3.13 --version # 3.13.xPin a version or use a lockfile
A request such as "24" lets each machine use any 24.x release. To make every machine use the same release, either pin or lock:
mise use --pin node@24writes the resolved version, such asnode = "24.21.0", tomise.toml. Thepinsetting makes this the default;--fuzzyoverrides it.- A lockfile keeps
node = "24"inmise.tomland records the resolved version, download URLs, and checksums inmise.lock.mise upgrademoves the lockfile within the request.
.tool-versions
mise reads asdf's .tool-versions files the same way as mise.toml: from the current directory and its parents. Use one when teammates still use asdf; otherwise mise.toml supports options, environment variables, and tasks that .tool-versions cannot express.
node 24.11.1 # comments are allowed
ruby 3 # a prefix
shellcheck latest
python 3.14 3.13 # several versions; the first is the default
go prefix:1.20 # newest 1.20.x, not the release named 1.20
shfmt path:./shfmt # use an existing directory
deno sub-1:latest # one major version below the latestasdf expects exact versions, so a shared file should hold the concrete versions that mise use --pin writes. Keep prefixes such as 3, latest, prefix:, sub-, backend names such as aqua:jqlang/jq, and most aliases out of a file that asdf users also read. When mise.toml and .tool-versions in the same directory both declare a tool, mise.toml wins. See Migrating from asdf for sharing a file with asdf users, and the asdf documentation for the file format.
Idiomatic version files
Idiomatic version files are the version files other tools already use, such as .nvmrc or .python-version. They let a project declare a version without requiring mise. mise reads them only for tools you enable:
mise settings add idiomatic_version_file_enable_tools nodeThey accept the same aliases as the tool, so an .nvmrc that contains lts/hydrogen works in both mise and nvm.
Enable idiomatic version files
idiomatic_version_file_enable_tools lists the tools whose idiomatic files mise reads. It is empty by default; see discussion #4345 for why. To stop reading them for a tool, for example because uv manages .python-version, remove that tool from the list in your global config, or run mise settings unset idiomatic_version_file_enable_tools to clear it.
To turn off one file while keeping the tool's others, add a tool:filename pair to idiomatic_version_file_disable_files. This keeps .nvmrc for Node.js but leaves package.json to package managers:
mise settings add idiomatic_version_file_disable_files node:package.jsonFinding and parsing these files has a small cost. Registry parsers run inside mise, while plugin-provided files can run the plugin's parser, and the results are cached.
Supported files
| Plugin | Idiomatic Files |
|---|---|
| atmos | .atmos-version |
| bazel | .bazelversion |
| bun | .bun-version, package.json |
| chezmoi | .chezmoiversion |
| cmake | CMakeLists.txt |
| crystal | .crystal-version |
| dagger | dagger.json |
| deno | .deno-version, package.json |
| dotnet | global.json |
| earthly | Earthfile |
| elixir | .exenv-version |
| go | .go-version, go.mod, go.work |
| golangci-lint | .golangci.yml, .golangci.yaml, .golangci.toml, .golangci.json |
| goreleaser | .config/goreleaser.yml, .config/goreleaser.yaml, .goreleaser.yml, .goreleaser.yaml, goreleaser.yml, goreleaser.yaml |
| java | .java-version, .sdkmanrc |
| lefthook | lefthook.yml, lefthook.yaml, .lefthook.yml, .lefthook.yaml, lefthook.toml, .lefthook.toml, lefthook.json, .lefthook.json, lefthook.jsonc, .lefthook.jsonc, .config/lefthook.yml, .config/lefthook.yaml, .config/lefthook.toml, .config/lefthook.json, .config/lefthook.jsonc |
| nim | .nim-version |
| node | .nvmrc, .node-version, package.json |
| npm | package.json |
| opentofu | .opentofu-version |
| packer | .packer-version |
| perl | .perl-version |
| pixi | pixi.toml, pyproject.toml |
| pnpm | package.json |
| pre-commit | .pre-commit-config.yaml |
| python | .python-version, .python-versions |
| ruby | .ruby-version, Gemfile |
| ruff | ruff.toml, .ruff.toml |
| rust | rust-toolchain.toml |
| swift | .swift-version |
| task | Taskfile.yml, Taskfile.yaml, taskfile.yml, taskfile.yaml |
| terraform | .terraform-version |
| terragrunt | .terragrunt-version |
| terramate | .terramate-version |
| yarn | .yvmrc, package.json |
| zig | .zig-version |
asdf and vfox plugins can declare more files of their own. Registry entries can describe how to extract a version from a structured file with the same version_regex, version_json_path, and version_expr parsers as the HTTP backend, so tools installed through backends such as aqua: and github: can read JSON manifests and other tool-specific files without a plugin. For .bazelversion values, see the Bazel cookbook.
asdf calls these files "legacy version files". mise calls them idiomatic version files to separate an ecosystem's own conventions from mise's configuration.
Which fields mise reads
mise reads only fields that declare the version a project is built with. It ignores fields that declare a minimum compatible version, which is a floor for the project's consumers. A library that still supports Node.js 18 or CMake 3.25 is almost certainly not developed with it, so resolving the floor would pin everyone to the oldest supported release or, read as a range, to the newest.
A configuration-format major is different. A GoReleaser config's version: 2 selects a schema that is tied to the CLI major, so mise reads it and selects the newest GoReleaser 2.x.
Deprecated minimum-version fields
mise used to read two floors as version requests: the go X.Y directive in go.mod and cmake_minimum_required in CMakeLists.txt. Both are deprecated, warn when they resolve a version, and stop being read in mise 2026.11.0. For Go, add a toolchain goX.Y.Z line to go.mod, or use .go-version or mise.toml. For CMake, use mise.toml.
To ignore the floors and silence the warning before then, set the idiomatic_version_file_ignore_minimum_versions setting. That setting is removed in 2026.11.0 along with the behavior it guards:
mise settings set idiomatic_version_file_ignore_minimum_versions trueIn package.json, mise reads development runtime and package-manager declarations, not engines compatibility ranges. See the Node.js guide for the fields, and the Bun and Deno guides for theirs.
For Go, mise reads the toolchain goX.Y.Z directive from go.mod or go.work, and an active workspace takes precedence over the modules beneath it. See the Go guide for examples and GOWORK behavior.