mise
mise manages versions of runtimes such as Node.js, pnpm and Java, and of command-line tools. This page covers installation, shell integration, global config, supply-chain checks, migrating from fnm, and common problems.
Installation#
Use the official installer. It installs a single binary that supports mise self-update. mise releases often, and the docs recommend staying on a recent version.
Install on macOS and Linux#
Run the official installer. The command is the same on macOS and Linux:
mise is installed to ~/.local/bin/mise.
Install on Windows#
Install with winget:
The winget build supports mise self-update.
Configuration#
The following settings are independent. Apply the ones you need.
Activate mise in the shell#
Add to ~/.zshrc:
Add to your PowerShell profile:
PowerShell supports mise activate and the chpwd hook. Only [shell_alias] is unsupported. The FAQ passage saying native Windows works only through shims is outdated; the shell compatibility table in the same docs is correct.
Add shims for non-interactive shells#
mise activate only works in interactive shells. Scripts, ssh host 'command', LaunchAgents and CI see none of the tools mise manages. When needed, add the shims to ~/.zprofile. It runs after macOS path_helper and is read by every login shell:
Shims resolve the version for the current directory, so per-project switching works in non-interactive shells too:
Place the shims in PATH as follows:
- After the installs directories that
mise activateprepends, as a fallback only. - Before Homebrew. Otherwise
brew install nodeshadows the version mise selected.
Global config file#
The global config lives at ~/.config/mise/config.toml. The path is the same on Windows: ~\.config\mise\. Example:
Global values are only fallbacks. A project's mise.toml, .node-version or the packageManager field in package.json overrides them.
- Java projects that need JDK 8 or 17 declare it in the project's
mise.toml. - Yarn 1 repositories must declare their version in
packageManager. Otherwise Yarn 4 migrates the lockfile to the Berry format. - For
minimum_release_ageand the exceptions on thevercelline, see Supply-chain checks.
Read versions from package.json#
mise calls .nvmrc, .node-version and the version fields in package.json idiomatic version files. They are all disabled by default. Enable them explicitly:
Once enabled, mise reads the packageManager and devEngines fields (jdx/mise#8059). This is enough to replace corepack for per-project pnpm versions.
mise does not read the traditional engines.node; the PR for it (#2288) was not merged. Projects that rely on engines.node need devEngines.runtime or a .node-version file instead.
Enable completions#
Load mise completions as follows:
-
Declare the
usagetool. The completion script calls theusageCLI at runtime. Homebrew installs it along with mise; the official installer and winget do not: -
Load completions after
activate.usageis managed by mise and is not on PATH before activation. Otherwise every new shell printsusage CLI not found:
On Windows, when PowerShell is the OpenSSH default shell, that warning makes scp fail.
Supply-chain checks#
mise's npm: backend installs through the embedded aube by default. aube runs three supply-chain checks:
- Trust downgrade check: blocks a dependency whose newer version lost its trusted-publisher evidence.
- Build script approval: follows pnpm's build approval model. A dependency's
preinstall,installandpostinstalldo not run by default. Your own project's scripts still run. - Release-age gate:
minimum_release_age, 24h by default. Only versions published longer ago than the threshold are installed, giving the community time to catch a compromised release. It mirrors pnpm'sminimumReleaseAgeand Renovate's equivalent.
The three checks are independent. When the trust policy blocks an install, changing minimum_release_age has no effect.
When an install is blocked, add the narrowest per-package exception instead of a global switch. See Troubleshooting.
npm.shell_out = true (use the npm CLI) and npm.package_manager = "pnpm" both bypass the trust policy for every package. The docs label shell_out a last resort. npm.shell_out still passes --ignore-scripts to npm, so it does not solve the build-script problem either.
Usage#
Migrate from fnm#
fnm options and their mise equivalents:
Uninstall fnm and remove its data:
-
Check that no process is using fnm's node:
A running node holds the exe inside
node-versionsopen.Remove-Itemsilently skips those files and leaves a directory that will not delete. -
Delete the data directories. node installs live in
%APPDATA%\fnm(Windows) or~/.local/share/fnm. Multishells live in%LOCALAPPDATA%\fnm_multishellsor~/.local/state/fnm_multishells.Multishells are junctions. Removing a link does not affect running processes, but those processes fail when they later spawn a child.
-
On Windows, uninstall the winget fnm package separately. Open a normal, non-elevated local PowerShell and run:
An elevated session fails with:
SSH sessions are elevated by default, so run it locally.
Troubleshooting#
self-update fails on a Homebrew install#
Running mise self-update on a Homebrew install fails with:
Cause: builds from package managers such as Homebrew cannot self-update and lag behind releases.
Fix: uninstall the package-manager build and install with the official installer.
Installs fail with GitHub rate limit exceeded#
Every install fails with:
Cause: mise queries the GitHub Releases API to resolve versions, and the anonymous quota is 60 requests per hour. mise reads a token from the gh CLI's hosts.yml by default (github.gh_cli_tokens is true). When gh stores its token in the system keyring, hosts.yml has no token.
Confirm the token is in the keyring:
Fix: in ~/.config/mise/config.toml, fetch the token on demand with a command:
The token is fetched only when mise needs it. It is not written to disk or exported to the environment.
Install fails with trust downgrade#
Installing an npm tool fails with:
Cause: an indirect dependency's older release carried trusted-publisher evidence and the newer one does not. Common causes are a manual publish, a backport that skipped the trusted workflow, or a mirror that strips metadata. It is not necessarily tampering. The AWS SDK's @smithy/* family behaves this way.
Fix: exempt the packages with trust_policy_excludes. Replace some-tool with the package you are installing:
A name with a version exempts only that version; a bare name exempts every version of the package. For frequently released families such as @smithy/*, use bare names.
Installed tool reports it is not compatible with Windows#
A tool installed through the npm: backend fails to run with:
Cause: the package downloads a platform binary in postinstall, and aube does not run dependency build scripts by default. The 479-byte file is not a PE file (header ec, not MZ). It is the author's "postinstall did not run" notice. The architecture is not the problem.
Fix: allow the package's build scripts with allow_builds:
allow_builds also takes an array to allow specific dependencies only: allow_builds = ["esbuild"].
Newly published version fails to install#
An npm package you just published cannot be installed for verification.
Cause: minimum_release_age defaults to 24h, so only versions published more than 24 hours ago are installed.
Fix: use either option. Replace @your-scope with your npm scope:
mise reports not trusted inside a config repository#
After you cd into a repository that backs up your configuration, mise reports not trusted, and node and pnpm stop working in that directory.
Cause: the repository contains its own .config/mise/config.toml, and mise loads it as a project config.
Fix: ignore that file with an environment variable. This is an early-init setting, so it has no effect in mise.toml. Add to ~/.zshenv, and replace the path with your repository's location:
References#
- Guany config: the configuration repository that contains the mise config on this page.