Introdução ao mise, o gerenciador de versões multilinguagem
Veja como o mise gerencia versões do Node e Python por projeto, arquivos de versão existentes, ferramentas fixadas, variáveis de ambiente e builds locais e na CI.
O mise é uma única ferramenta de linha de comando que instala e alterna versões de Node, Python, Ruby e outros runtimes por diretório, lendo essas versões de um arquivo mise.toml na raiz do projeto.
Se o seu repositório tem um frontend com Vite e um script Python que gera conteúdo antes do build, é provável que você esteja usando nvm e pyenv lado a lado, torcendo para que o shell de cada colega de equipe esteja alinhado com o CI. Geralmente, algum deles não está.
Para uma comparação lado a lado entre mise, nvm, pyenv, rustup e SDKMAN!, veja 5 Version Managers Every Developer Should Know. Este artigo deixa de lado a lista de recursos. Em vez disso, ele pega um repositório e o acompanha passando por cd, arquivos .nvmrc existentes, o primeiro clone de um colega, o CI, uma task de build com dois runtimes e variáveis de ambiente.
Principais conclusões
- Com a ativação no shell, entrar em um diretório que tenha um
mise.tomlcoloca no PATH os runtimes fixados por aquele projeto, e sair dele restaura as versões anteriores. - O mise ignora
.nvmrce.python-version, a menos que você os habilite por ferramenta com a configuraçãoidiomatic_version_file_enable_tools. - O
mise runcarrega por conta própria as ferramentas e o env do projeto e, por padrão, instala as ferramentas que estiverem faltando, então funciona no CI sem ativação no shell. - O
jdx/mise-action@v4instala o mise e as ferramentas definidas nomise.toml. Se houver ummise.lockcommitado, ele instala com--locked. - A tabela
[env]é texto puro que vai para o repositório. Ela serve para configuração, não para secrets.
O projeto: um frontend Vite com uma etapa de build em Python
O repositório de exemplo, docs-preview, tem dois runtimes, um arquivo de configuração e um workflow:
docs-preview/
├── content/*.md
├── scripts/build_content.py
├── src/
├── package.json # vite in devDependencies
├── mise.toml
└── .github/workflows/build.yml
O script Python usa apenas a biblioteca padrão. Ele converte os arquivos Markdown em JSON, que o frontend importa:
# scripts/build_content.py
import json, os, pathlib
src = pathlib.Path(os.environ.get("CONTENT_DIR", "content"))
out = pathlib.Path("src/generated/content.json")
out.parent.mkdir(parents=True, exist_ok=True)
items = [{"slug": p.stem, "body": p.read_text(encoding="utf-8")}
for p in sorted(src.glob("*.md"))]
out.write_text(json.dumps(items, indent=2), encoding="utf-8")
print(f"wrote {len(items)} items to {out}")
Este é o mise.toml completo. As próximas seções fazem referência a ele:
[tools]
node = "24"
python = "3.14"
[settings]
lockfile = true
[env]
CONTENT_DIR = "content"
VITE_SITE_NAME = "Docs Preview"
[tasks.install]
description = "Install JS dependencies"
run = "npm ci"
[tasks."build:content"]
description = "Convert content files to JSON for the frontend"
run = "python scripts/build_content.py"
[tasks.build]
description = "Generate content, then build the Vite app"
depends = ["install", "build:content"]
run = "npx vite build"
A tabela [tools] usa prefixos de versão (Node 24 LTS, Python 3.14). O lockfile, abordado mais adiante, registra as versões de patch exatas para as quais eles são resolvidos.
O que acontece quando você entra e sai do diretório com cd
Com o mise ativado, entrar em um diretório que contém um mise.toml coloca no seu PATH os runtimes fixados por aquele projeto. Sair dele restaura as versões que estavam ativas antes. Depois que o mise activate estiver no arquivo de inicialização do seu shell, o mise troca as ferramentas e as variáveis de ambiente toda vez que você muda de diretório.
cd ~
node --version # whatever your system or nvm provides
cd ~/code/docs-preview
node --version # v24.x from mise.toml
python3 --version # Python 3.14.x
echo "$CONTENT_DIR" # content
O momento em que o mise troca as versões depende do shell. De acordo com a documentação de shims, bash, zsh, fish e xonsh trocam assim que você executa cd. Outros shells esperam até o próximo prompt aparecer.
Quando uma versão fixada ainda não está instalada
Em uma máquina nova, execute mise install no diretório do projeto. Essa é a solução explícita e previsível. As tasks também resolvem isso para você: as tasks do mise são executadas com as ferramentas e variáveis de ambiente do projeto, e a configuração auto_install, habilitada por padrão, instala as ferramentas configuradas que estiverem faltando quando você chama mise run. O Python exige atenção se você depende de shims. A referência de configurações explica que um shim que não consegue resolver uma versão gerenciada pelo mise (por exemplo, quando o auto-install está desabilitado) recorre ao primeiro programa com o mesmo nome encontrado em outro lugar do PATH. Para uma ferramenta que o sistema operacional também fornece, como python3, isso significa que a sua versão fixada nunca é executada e você não recebe nenhum erro.
Para fixar uma versão diferente apenas em um terminal, use mise shell node@<version>. Isso exige um shell em que o mise já esteja ativado.
Arquivos .nvmrc e .python-version existentes
O mise não lê .nvmrc nem .python-version, a menos que você habilite isso para cada ferramenta com idiomatic_version_file_enable_tools. O FAQ do mise confirma que esses arquivos de versão idiomáticos ficam desabilitados por padrão. Esse padrão chegou no mise 2025.10.0. Para habilitá-los:
[settings]
idiomatic_version_file_enable_tools = ["node", "python"]
A documentação de configuração lista o package.json entre os arquivos que o mise lê para node, então habilitar node também pode fazer com que esse arquivo seja considerado. Para ignorar um único arquivo, adicione um par tool:filename, como node:package.json, à configuração idiomatic_version_file_disable_files.
Depois que o mise.toml fixar os dois runtimes, mantenha o .nvmrc apenas para os colegas que ainda usam nvm e garanta que os dois arquivos estejam de acordo. Se precisar relembrar como o nvm trata esse arquivo, veja os guias de como alternar versões do Node com nvm no macOS, no Linux e no Windows.
Colegas de equipe e CI
Um notebook e um runner de CI leem o mesmo mise.toml, mas colocam as ferramentas no PATH de formas diferentes:
| Notebook | GitHub Actions | |
|---|---|---|
| Ferramentas no PATH | Hook de ativação no shell | jdx/mise-action instala o mise e as ferramentas fixadas |
| Origem das versões | mise.toml + mise.lock | Os mesmos arquivos |
| Comando de build | mise run build | mise run build |
O primeiro clone de um colega:
- Instale o mise:
curl https://mise.run | sh - Adicione
eval "$(~/.local/bin/mise activate zsh)"(ou a linha correspondente ao seu shell) ao arquivo rc do seu shell. - Revise o
mise.tomle, em seguida, executemise install. - Execute
mise run build.
O modelo de confiança do mise exige atenção, porque arquivos de configuração podem executar código. Segundo o guia de primeiros passos, fora do CI e do modo paranoid, qualquer comando que atue sobre o projeto, como mise install, mise exec ou mise run, confia automaticamente na configuração ativa. Por isso, revise o mise.toml antes de executar qualquer um deles e use mise trust quando quiser confiar em uma configuração de forma explícita.
Trave as versões exatas. O lockfile, mise.lock, é criado pelo mise lock ou pela configuração lockfile = true mostrada acima. Faça commit dele. Com mise install --locked, uma entrada ausente no lockfile vira um erro, então o mise nunca escolhe uma nova versão silenciosamente.
Workflow de CI:
# .github/workflows/build.yml
name: build
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: jdx/mise-action@v4
- run: mise run build
O step do mise-action instala o mise e as ferramentas definidas no mise.toml, de modo que o workflow usa as mesmas versões que os desenvolvedores usam localmente. Por padrão, ele executa mise install (install: true) e faz cache das ferramentas (cache: true). Quando o mise.lock está presente, ele instala com --locked. Ele também repassa ${{ github.token }} automaticamente. Nos notebooks, definir GITHUB_TOKEN ou MISE_GITHUB_TOKEN ajuda caso as instalações esbarrem em limites de taxa (rate limits), conforme descrito na página sobre tokens do GitHub.
Quando algo quebra, três comandos ajudam a isolar o problema:
| Sintoma | Comando |
|---|---|
| A ativação ou a instalação parece incorreta | mise doctor |
| O arquivo de configuração errado parece estar sendo aplicado | mise config ls |
| Versão errada selecionada | mise ls --current |
Uma task real: mise run build com dois runtimes
Uma task definida no mise.toml é executada com as ferramentas fixadas do projeto e as variáveis de [env] já aplicadas. Isso significa que mise run build usa o mesmo Node e o mesmo Python no notebook e no CI, mesmo sem ativação no shell.
A chave depends faz com que build espere até que todas as tasks listadas tenham terminado, garantindo que a etapa em Python já tenha gravado src/generated/content.json antes de o Vite ler o arquivo. As tasks listadas podem ser executadas simultaneamente. A documentação de tasks afirma que os pré-requisitos podem rodar em paralelo e que a ordem deles em depends não estabelece uma sequência. Isso é seguro aqui porque o npm ci grava em node_modules e o script Python grava em src/generated, então nenhuma das etapas mexe na saída da outra. Se, em algum momento, uma etapa passar a consumir a saída da outra, faça com que ela dependa diretamente dessa etapa.
mise tasks # lists install, build:content, build
mise run build # npm ci + Python step, then vite build
O guia de execução de tasks define o limite padrão em oito jobs paralelos.
Variáveis de ambiente por projeto com o mise
Os valores na tabela [env] são texto puro em um arquivo commitado. O env do mise é gerenciamento de configuração, não gerenciamento de secrets. No exemplo, o script Python lê CONTENT_DIR por meio de os.environ, e o frontend lê import.meta.env.VITE_SITE_NAME.
O prefixo VITE_ torna concreto o risco de valores em texto puro no [env]. A documentação de variáveis de ambiente do Vite explica que qualquer variável que comece com VITE_ acaba no bundle do cliente, com o valor inserido no código em tempo de build. Qualquer valor VITE_ no mise.toml se torna público assim que o site vai para o ar.
Uma variável de build ausente não faz o build falhar. Você obtém um bundle que chama a URL errada. O session replay pode mostrar isso do ponto de vista do usuário: você vê as requisições indo para uma URL base undefined e, a partir daí, rastreia o problema até o ambiente em que o build foi executado.
Quando vale a pena usar o mise?
Se um projeto precisa apenas de Node, o nvm e um .nvmrc já resolvem, e o mise é opcional. Os guias de nvm cobrem bem essa configuração. Vale a pena adotar o mise quando um único repositório fixa dois ou mais runtimes e o CI precisa ser igual a todos os notebooks. Para testá-lo em um repositório que você já tem, adicione um mise.toml com as versões fixadas em [tools], execute mise lock, faça commit dos dois arquivos e altere o step de build do seu CI para mise run build.
Perguntas frequentes
Onde devo guardar secrets se o mise.toml é commitado?
Guarde os secrets em um mise.local.toml incluído no .gitignore, ou declare-os no mise.toml com required = true, o que faz o mise verificar se a variável está definida sem armazenar nenhum valor. Adicionar redact = true mascara os valores na saída capturada das tasks, mas o mise env continua exibindo-os em texto puro. Para secrets que precisam ser commitados, o mise consegue descriptografar arquivos SOPS criptografados com age (um recurso experimental) para mise exec, tasks e ativação no shell.
O mise lê arquivos .tool-versions do asdf?
Sim. Diferentemente do .nvmrc, o mise lê o .tool-versions sem nenhuma configuração extra. No Unix, ele também consegue executar plugins de shell do asdf, embora não haja garantia de que todo comando ou plugin do asdf funcione. Se o mise.toml e o .tool-versions no mesmo diretório declararem a mesma ferramenta, o mise.toml prevalece. A documentação do mise desaconselha compartilhar diretórios de instalação entre o asdf e o mise, então execute mise install depois de fazer a migração.
Por que meu editor ou script usa uma versão do Node diferente da do meu terminal?
Editores, git hooks e agendadores muitas vezes não carregam o seu arquivo rc interativo, então o hook de ativação do mise nunca é executado. Para corrigir isso, adicione mise activate zsh --shims (ou a linha correspondente ao seu shell) a um perfil de login que o seu editor leia, como o ~/.zprofile, e mantenha o mise activate simples no ~/.zshrc. Para scripts, use mise exec -- comando ou mise run. O modo de shims deixa de lado alguns recursos da ativação, como a maioria dos hooks.