Pular para o conteúdo
Cursos

DevClub

LógicaFront-endBack-endMobile

IA Club

IA na prática
Estudar programaçãoEstudar IA
LiçãoIniciantecódigo testado

Instalar o Node.js com nvm e trocar de versão por projeto

Instalar o nvm no Linux, macOS e Windows, fixar a versão do projeto com .nvmrc e resolver o command not found que aparece depois de instalar.

Rodolfo Mori11 min de leitura

O nvm guarda várias versões do Node.js no seu computador e deixa você escolher, por pasta, qual delas responde pelo comando node. É por isso que ele é a forma recomendada de instalar o Node: um comando troca a versão inteira, e um arquivo de uma linha registra qual versão o projeto usa.

Os exemplos aqui são de uma escola de idiomas, a Escola Aurora, que tem um script de relatório de matrículas. O mesmo script vai rodar em uma versão e quebrar em outra — e é isso que faz o nvm valer a pena.

O nvm é um gerenciador de versões. Em palavras simples, ele mantém várias instalações do Node separadas e troca qual executável aparece quando você roda node, sem obrigar todos os projetos a usar o mesmo número.

A gaveta de ferramentas de cada projeto

Numa oficina, duas máquinas podem exigir chaves do mesmo formato em tamanhos diferentes. Jogar fora uma chave toda vez que muda de máquina cria trabalho e erro; uma gaveta identificada permite pegar a medida certa. O nvm é a gaveta, a versão do Node é a ferramenta e o .nvmrc é a etiqueta deixada pelo projeto.

Antes e depois de cada nvm use, rode os comandos de versão mostrados na lição e anote o caminho do executável. A microprática confirma duas mudanças: o número respondido por node e o binário que o shell encontrou. Assim você não depende apenas da mensagem de sucesso do nvm.

Quando você baixa o Node em nodejs.org e roda o instalador, o node vai para uma pasta do sistema. Existe um Node na máquina, e trocar de versão significa desinstalar e instalar de novo.

Isso funciona enquanto você tem um projeto. Some no dia em que você tem dois: o site da escola roda em Node 18 porque a hospedagem é antiga, e a API nova roda em Node 24 porque usa recursos que o 18 não tem. Com um Node global, um dos dois está sempre quebrado.

O nvm resolve por um caminho simples: ele não instala o Node no sistema. Instala tudo dentro de uma pasta sua, e mexe no PATH do terminal para apontar para a versão que você escolheu. Trocar de versão é mudar o PATH, o que leva milissegundos e não pede senha de administrador.

Instalando o nvm no Linux e no macOS

O instalador é um script. Você baixa e executa numa linha:

bash
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash

Feche o terminal e abra de novo — esse passo não é opcional, e a próxima seção explica por quê. Agora confira que o nvm respondeu:

bash
nvm --version
nvm ls
0.40.3

-> system * iojs -> N/A (default) node -> stable (-> N/A) (default) unstable -> N/A (default)

Repare que nenhum Node foi instalado ainda. O nvm é só o gerenciador; o system que aparece ali é o Node que já existia na máquina, fora do controle dele. Instalar a versão de longo suporte é o segundo comando:

bash
nvm install --lts
Installing latest LTS version. Downloading and installing node v24.19.0... Downloading https://nodejs.org/dist/v24.19.0/node-v24.19.0-darwin-arm64.tar.xz... Computing checksum with sha256sum Checksums matched! Now using node v24.19.0 (npm v11.17.0) Creating default alias: default -> lts/* (-> v24.19.0 *)

(As linhas da barra de progresso foram retiradas.) A última linha é a parte que importa: o nvm criou o apelido default, que é a versão que todo terminal novo vai usar.

Agora as outras duas versões da Escola Aurora:

bash
nvm install 18.20.8
nvm install 22
Downloading and installing node v18.20.8... Downloading https://nodejs.org/dist/v18.20.8/node-v18.20.8-darwin-arm64.tar.xz... Computing checksum with sha256sum Checksums matched! Now using node v18.20.8 (npm v10.8.2) Downloading and installing node v22.23.2... Downloading https://nodejs.org/dist/v22.23.2/node-v22.23.2-darwin-arm64.tar.xz... Computing checksum with sha256sum Checksums matched! Now using node v22.23.2 (npm v10.9.8)

Você pediu 22 sem o resto e o nvm completou sozinho para v22.23.2, a mais nova daquela linha. Vale para nvm install 18, nvm use 20 e por aí vai.

nvm ls agora mostra o inventário completo. A seta marca a versão ativa — e ela está no 24 porque este nvm ls rodou num terminal novo, que abre sempre no default:

bash
nvm ls
v18.20.8 * v22.23.2 * -> v24.19.0 * system * default -> lts/* (-> v24.19.0 *) iojs -> N/A (default) node -> stable (-> v24.19.0 *) (default) stable -> 24.19 (-> v24.19.0 *) (default) unstable -> N/A (default) lts/* -> lts/krypton (-> v24.19.0 *) lts/argon -> v4.9.1 (-> N/A) lts/boron -> v6.17.1 (-> N/A) lts/carbon -> v8.17.0 (-> N/A) lts/dubnium -> v10.24.1 (-> N/A) lts/erbium -> v12.22.12 (-> N/A) lts/fermium -> v14.21.3 (-> N/A) lts/gallium -> v16.20.2 (-> N/A) lts/hydrogen -> v18.20.8 * lts/iron -> v20.20.2 (-> N/A) lts/jod -> v22.23.2 * lts/krypton -> v24.19.0 *

As três primeiras linhas são as versões que o nvm baixou; a quarta, system, é o Node que já estava na máquina. Da quinta em diante são apelidos. Aquelas palavras esquisitas — hydrogen, jod, krypton — são os codinomes das linhas de LTS, e nvm use lts/jod funciona igual a nvm use 22. Os apelidos seguidos de N/A existem, mas apontam para versões que você não baixou.

Windows: outro programa, quase os mesmos comandos

O nvm é um script de shell. No Windows nativo ele não roda. Existem duas saídas, e as duas são legítimas:

caminho como instalar .nvmrc precisa de administrador
WSL (Ubuntu no Windows) o mesmo curl da seção acima, dentro do WSL sim não
nvm-windows winget install CoreyButler.NVMforWindows não sim, terminal como admin

Com o nvm-windows, os comandos do dia a dia mudam pouco:

bash
nvm install 24.19.0
nvm use 24.19.0
nvm list

Três diferenças que pegam gente: não existe nvm install --lts (você digita o número), nvm use não lê o .nvmrc da pasta, e o terminal precisa estar aberto como administrador porque o nvm-windows troca a versão mexendo num link simbólico dentro de Program Files.

Se você vai trabalhar com back-end de verdade no Windows, o WSL é o caminho mais tranquilo: é o mesmo Linux que roda no servidor, com os mesmos comandos deste artigo.

LTS ou Current: qual número entra no projeto

O Node lança uma versão nova a cada seis meses. As de número par viram LTS (long-term support) e ganham correção por cerca de trinta meses. As de número ímpar são Current: servem para experimentar recurso novo e saem de suporte em seis meses.

Para ver o que existe de LTS:

bash
nvm ls-remote --lts | tail -8
v24.14.0 (LTS: Krypton) v24.14.1 (LTS: Krypton) v24.15.0 (LTS: Krypton) v24.16.0 (LTS: Krypton) v24.17.0 (LTS: Krypton) v24.18.0 (LTS: Krypton) v24.18.1 (LTS: Krypton) -> v24.19.0 * (Latest LTS: Krypton)

A regra é curta: o projeto roda a mesma versão que a produção roda. Se a hospedagem da escola está em Node 22, o .nvmrc diz 22, mesmo que o 24 já exista. Versão diferente entre a sua máquina e o servidor é a origem clássica do “na minha máquina funciona”.

Você pode registrar essa exigência no package.json, e o npm passa a avisar:

json
{
  "name": "escola-aurora",
  "type": "module",
  "engines": { "node": ">=22" },
  "packageManager": "pnpm@10.4.1",
  "scripts": {
    "relatorio": "node matriculas.mjs"
  }
}

Rodando npm install com o Node 18 ativo:

npm warn EBADENGINE Unsupported engine { npm warn EBADENGINE package: undefined, npm warn EBADENGINE required: { node: '>=22' }, npm warn EBADENGINE current: { node: 'v18.20.8', npm: '10.8.2' } npm warn EBADENGINE }

up to date in 468ms

É aviso, não erro: o npm instala mesmo assim. O engines documenta a intenção; quem garante a versão é o .nvmrc. O "type": "module" que aparece logo acima é outra decisão de versão disfarçada — ele escolhe entre import e require, e está explicado em ESM ou CommonJS no Node.

Fixando a versão do projeto no .nvmrc

O .nvmrc é um arquivo de uma linha, na raiz do projeto, com a versão. Você não precisa criar na mão:

bash
nvm use --save 24.19.0
cat .nvmrc
Wrote version number (v24.19.0) to .nvmrc Now using node v24.19.0 (npm v11.17.0) v24.19.0

A partir daí, nvm use sem argumento nenhum lê o arquivo. Estando no Node 18 e entrando na pasta da escola:

bash
node -v
nvm use
node -v
v18.20.8 Found '/private/tmp/escola-aurora/.nvmrc' with version <v24.19.0> Now using node v24.19.0 (npm v11.17.0) v24.19.0

Esse arquivo vai para o Git. É ele que diz para a próxima pessoa — e para você daqui a seis meses — em que versão este projeto foi escrito.

E se o .nvmrc pedir uma versão que a máquina não tem? O nvm avisa e ensina a saída:

bash
nvm use
Found '/private/tmp/escola-aurora/.nvmrc' with version <v20.20.2> N/A: version "v20.20.2" is not yet installed.

You need to run nvm install to install and use the node version specified in .nvmrc.

bash
nvm install
Found '/private/tmp/escola-aurora/.nvmrc' with version <v20.20.2> Downloading and installing node v20.20.2... Downloading https://nodejs.org/dist/v20.20.2/node-v20.20.2-darwin-arm64.tar.xz... Computing checksum with sha256sum Checksums matched! Now using node v20.20.2 (npm v10.8.2)

Ou seja: nvm install também lê o .nvmrc. Ao clonar um projeto novo, os dois primeiros comandos são sempre nvm install e depois o instalador de pacotes.

Cada versão traz o próprio npm — e os próprios globais

Trocar de Node não muda só o node. Muda o npm junto:

bash
for v in 18 22 24; do nvm use $v > /dev/null; echo "node $(node -v)  npm v$(npm -v)"; done
node v18.20.8 npm v10.8.2 node v22.23.2 npm v10.9.8 node v24.19.0 npm v11.17.0

E muda também onde os pacotes globais moram:

bash
nvm use 18 > /dev/null && npm root -g
nvm use 24 > /dev/null && npm root -g
/private/tmp/nvm-escola/versions/node/v18.20.8/lib/node_modules /private/tmp/nvm-escola/versions/node/v24.19.0/lib/node_modules

Caminhos diferentes, pastas diferentes. Um npm install -g feito no Node 24 simplesmente não existe no Node 18 — e é aí que aparece o Cannot find module mais frustrante de diagnosticar, porque o pacote está instalado, só que na outra versão. Por isso npx costuma ser melhor que instalar global.

A mesma pasta, o mesmo script, duas versões

Agora a prova de que isso não é teoria. O relatório de matrículas da escola usa Object.groupBy, que chegou ao Node na versão 21:

js
const matriculas = [
  { aluno: 'Ana Prado', turma: 'ingles-b1', mensalidade: 320 },
  { aluno: 'Bruno Sales', turma: 'espanhol-a2', mensalidade: 280 },
  { aluno: 'Carla Reis', turma: 'ingles-b1', mensalidade: 320 },
  { aluno: 'Diego Luz', turma: 'ingles-a1', mensalidade: 260 },
];

const porTurma = Object.groupBy(matriculas, (m) => m.turma);

for (const [turma, alunos] of Object.entries(porTurma)) {
  const total = alunos.reduce((soma, m) => soma + m.mensalidade, 0);
  console.log(`${turma}: ${alunos.length} aluno(s), R$ ${total}`);
}

Com o Node 24 ativo:

bash
nvm use 24 > /dev/null
node -v
node matriculas.mjs
v24.19.0 ingles-b1: 2 aluno(s), R$ 640 espanhol-a2: 1 aluno(s), R$ 280 ingles-a1: 1 aluno(s), R$ 260

Mesma pasta, mesmo arquivo, trocando só a versão:

bash
nvm use 18 > /dev/null
node -v
node matriculas.mjs
v18.20.8 file:///private/tmp/escola-aurora/matriculas.mjs:8 const porTurma = Object.groupBy(matriculas, (m) => m.turma); ^

TypeError: Object.groupBy is not a function at file:///private/tmp/escola-aurora/matriculas.mjs:8:25 at ModuleJob.run (node:internal/modules/esm/module_job:195:25) at async ModuleLoader.import (node:internal/modules/esm/loader:337:24) at async loadESM (node:internal/process/esm_loader:34:7) at async handleMainPromise (node:internal/modules/run_main:106:12)

Node.js v18.20.8

O erro não é do seu código. É o Node 18 dizendo que Object.groupBy não existe naquela versão do motor. A última linha do stack trace é o que resolve o caso em dois segundos: Node.js v18.20.8. Sempre leia essa linha antes de sair mexendo no código — como em qualquer erro de JavaScript, a mensagem já traz o diagnóstico.

Opções de linha de comando também nascem numa versão. O --run, que executa um script do package.json sem passar pelo npm, chegou no Node 22:

bash
nvm use 24 > /dev/null && node --run relatorio
nvm use 18 > /dev/null && node --run relatorio
ingles-b1: 2 aluno(s), R$ 640 espanhol-a2: 1 aluno(s), R$ 280 ingles-a1: 1 aluno(s), R$ 260 node: bad option: --run

nvm: command not found depois de fechar o terminal

Este é o problema número um de quem acabou de instalar. Você instala, funciona, fecha o terminal, abre de novo e:

bash
nvm ls
bash: nvm: command not found

Não é instalação corrompida. O nvm não é um programa — é uma função de shell que precisa ser carregada em cada terminal que abre. Num terminal em que ele está funcionando, dá para confirmar isso:

bash
which nvm
echo "codigo de saida: $?"
type -t nvm
codigo de saida: 1 function

which não achou nada (código de saída 1) porque não existe arquivo nvm em lugar nenhum do PATH. Já type -t responde function. O instalador tenta escrever a linha que carrega essa função no seu arquivo de perfil; quando ele não encontra o arquivo, ou quando você usa um shell que ele não previu, nada é escrito e o command not found aparece.

A correção é acrescentar estas três linhas ao fim do ~/.zshrc (macOS e quem usa zsh) ou do ~/.bashrc (a maioria das distribuições Linux):

bash
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"

Depois, source ~/.zshrc ou feche e abra o terminal.

O apelido default decide a versão de cada terminal novo, e ele não muda o terminal que já está aberto:

bash
nvm alias default 22
nvm current
default -> 22 (-> v22.23.2 *) v24.19.0

O apelido virou 22, mas a sessão atual continua no 24. O próximo terminal é que abre no 22.

corepack: pnpm e yarn sem instalar nada global

Se o projeto da escola usa pnpm ou yarn, você não precisa de npm install -g nenhum. O Node já vem com o corepack, que lê o campo packageManager do package.json e baixa exatamente aquela versão:

bash
corepack enable
pnpm -v
! Corepack is about to download https://registry.npmjs.org/pnpm/-/pnpm-10.4.1.tgz 10.4.1

O 10.4.1 não foi escolha do corepack: é o "packageManager": "pnpm@10.4.1" do package.json que você viu acima. Todo mundo do time roda a mesma versão do gerenciador, sem combinar nada — a mesma ideia do .nvmrc, uma camada acima.

Só lembre que o corepack enable cria os atalhos dentro da versão ativa, como qualquer global. Instalou um Node novo com o nvm? Rode o corepack enable de novo nele.

O que vem depois

Com o nvm instalado, o .nvmrc no repositório e o terminal carregando a função em toda sessão, o ambiente está pronto. O próximo passo é entender o que o Node faz com o seu arquivo: comece por o que é o Node.js se você ainda não leu, siga para npm e package.json para instalar a primeira dependência e veja a ordem completa no guia de Node.js. A trilha de Node mostra onde cada assunto entra.

  • node
  • nvm
  • instalacao
  • versionamento
  • terminal

Perguntas frequentes

Preciso desinstalar o Node que eu já tinha antes de usar o nvm?
Não é obrigatório, mas ajuda. Se sobrar um Node instalado pelo pacote do sistema, ele continua no PATH como system e volta a valer sempre que o nvm não estiver carregado. Desinstalar evita horas de confusão.
O nvm funciona no Windows?
O nvm original é um script de shell e roda no WSL. No Windows nativo você usa outro programa, o nvm-windows, que tem os mesmos comandos principais mas não lê .nvmrc sozinho e precisa de terminal como administrador.
Cada versão do Node tem os próprios pacotes globais?
Tem. O npm root -g aponta para uma pasta dentro da versão ativa, então um pacote instalado com -g no Node 24 não existe no Node 18. Trocou de versão, reinstale o global ou use npx.
Qual versão do Node eu coloco num projeto novo?
A LTS mais recente, e a mesma que o servidor de produção roda. Versão Current serve para testar recurso novo, não para o projeto que você precisa manter no ar.

Dúvidas e comentários

Travou em algum passo? Pergunte aqui — a equipe e outros alunos respondem.

Todo o código deste artigo foi executado em nvm 0.40.3 com Node 18.20.8, 20.20.2, 22.23.2 e 24.19.0 no macOS ARM, e as saídas exibidas são as reais — como produzimos este conteúdo.

Fontes consultadas

  1. nvm — Node Version Manager (repositório oficial) — github.com
  2. Node.js — Releases e calendário de suporte — nodejs.org
  3. nvm-windows — Node Version Manager para Windows — github.com

Continue por aqui