28 min

npm vs Yarn vs pnpm vs Bun: qual usar em 2026?

Gregory Serrao
npm, Yarn, pnpm ou Bun? Compare arquitetura, lockfiles, monorepos, segurança e um benchmark reproduzível antes de escolher.

Seu projeto tem package.json, node_modules e um comando de instalação. Então trocar npm por pnpm, Yarn ou Bun deveria ser só mudar uma palavra, certo?

Não.

Os quatro resolvem dependências, geram lockfile e executam scripts. Mas eles não materializam a árvore da mesma maneira, não expõem os mesmos pacotes, não tratam scripts de instalação com a mesma política e não oferecem o mesmo modelo para monorepos. Uma troca pode reduzir o tempo da integração contínua (CI) — ou revelar imports que só funcionavam por acidente, quebrar um addon nativo e criar duas fontes de verdade.

A bancada deste guia compara npm 12.0.2, pnpm 11.24.0, Yarn 4.18.0 e Bun 1.4.0 como gerenciadores de pacotes. Em vez de repetir o benchmark do fabricante, rodei os quatro sobre a mesma API TypeScript, na mesma máquina, com lockfiles próprios, cache frio e quente, cinco e dez execuções por cenário e uma validação de build e teste no final.

O teste foi fechado em 30 de agosto de 2026 e permanece congelado nessas versões para continuar auditável. Na conferência de publicação, em 7 de setembro, os latest eram npm 12.0.2, pnpm 12.3.4, Yarn 4.18.0 e Bun 1.4.2. As orientações abaixo consideram as linhas atuais; os números de desempenho continuam atribuídos somente às versões que foram executadas.

O resultado mais importante não é qual comando terminou primeiro. É que uma das configurações mais rápidas não conseguiu compilar a fixture. Velocidade sem compatibilidade não vence comparação nenhuma.

TL;DR: qual usar?

  • Continue com o atual se o repositório está estável e você não consegue apontar uma dor mensurável. Migração também custa tempo e risco.
  • Use npm quando simplicidade, familiaridade e compatibilidade com o node_modules tradicional dominam a decisão.
  • Use pnpm para muitos projetos, monorepos, filtros fortes, store compartilhada e uma estrutura de dependências mais disciplinada.
  • Use Yarn moderno quando PnP, Constraints, Zero-Installs ou extensibilidade são requisitos reais — e a equipe consegue manter essa configuração.
  • Use Bun quando o conjunto de ferramentas (toolchain) Bun está na estratégia ou quando você validou o package manager no seu projeto Node. Instalar com Bun e executar com Bun são decisões diferentes.

Minha recomendação geral é menos emocionante do que um ranking: npm é o padrão de menor atrito; pnpm é o ponto de partida mais forte para equipes e monorepos; Yarn e Bun ganham quando seus diferenciais resolvem um requisito específico.

Seu cenário Escolha inicial O que provar antes
API ou aplicação simples npm npm ci, test, build e pack
Vários projetos na mesma máquina pnpm economia incluindo a store, não só node_modules
Monorepo novo pnpm ou Yarn moderno filtros, publicação, peers e ferramentas reais do projeto
PnP, Constraints ou Zero-Installs Yarn moderno IDE, TypeScript, addons e bundlers
Runtime Bun já planejado Bun “Bun instala, Node executa” separado de “Bun executa”
Projeto legado com plugins antigos npm ou linker hoisted quem percorre node_modules manualmente
Repositório sem dor concreta mantenha o atual crie uma linha de base antes de reabrir a decisão

Se preferir uma indicação pelo seu contexto, responda ao quiz de gerenciadores de pacotes. Ele também pode responder “não migre”.

Neste guia

[[codeinit-anchor:camadas]]

Antes de comparar: não misture as camadas

Uma parte da confusão vem de colocar ferramentas diferentes no mesmo saco:

Camada Responsabilidade Exemplos
runtime executa JavaScript Node.js, Bun
gerenciador de versão instala e alterna runtimes nvm, fnm, Volta, mise
package manager resolve e instala dependências npm, pnpm, Yarn, Bun
seletor da versão do package manager entrega a interface de linha de comando (CLI) declarada pelo projeto Corepack
workspace liga pacotes do mesmo repositório recursos dos quatro gerenciadores
orquestrador ordena tarefas e faz cache de build Nx, Turborepo

Trocar npm por pnpm não troca o Node. Adotar workspaces não adiciona cache remoto. Rodar bun install não obriga executar a aplicação com o runtime Bun.

Glossário mínimo para acompanhar a comparação

  • lockfile: arquivo versionado com a resolução concreta das dependências;
  • linker: estratégia que torna os pacotes instalados acessíveis ao código;
  • hoisted: pacotes compartilhados são elevados para uma pasta comum;
  • store: armazenamento reutilizado por mais de um projeto;
  • hardlink/symlink: referências do filesystem que evitam ou organizam cópias;
  • fixture: projeto pequeno e controlado usado como objeto do teste;
  • lifecycle script: código executado durante etapas como instalação;
  • peer dependency: dependência que o pacote espera encontrar no projeto consumidor, em uma faixa compatível, em vez de controlar sozinho;
  • age gate: espera mínima antes de aceitar uma versão recém-publicada.
  • CI (integração contínua): pipeline que instala, testa e empacota cada mudança;
  • CLI (interface de linha de comando): programa operado por comandos no terminal.

Também não confunda engines.node com um pin exato. O campo normalmente declara uma faixa de compatibilidade. Para escolher a versão usada pela equipe, use um arquivo ou tool manager próprio. nvm, fnm, Volta e mise resolvem essa camada; o tutorial de instalação do NVM continua separado para não misturar intenção de escolha com passo a passo.

[[codeinit-anchor:benchmark]]

O benchmark CodeInit

Benchmarks de package manager são fáceis de manipular sem mentir. Basta comparar uma cache quente contra outra fria, medir o Yarn Classic no lugar do Yarn atual, ignorar a store compartilhada ou divulgar o menor valor entre várias tentativas.

Aqui a fixture é uma API Fastify 5 e TypeScript 7 com 19 dependências diretas, incluindo plugins Fastify, Zod, Pino, JOSE, Undici, ESLint e Vitest. As 19 versões diretas são exatas; cada gerenciador produz sua própria árvore transitiva, que não foi presumida idêntica. O harness e os dados brutos acompanham o artigo.

Ambiente e protocolo

  • Apple M2, 16 GB, macOS 26.5.2, APFS e arquitetura arm64;
  • Node.js 22.23.0 para o harness e para executar a aplicação;
  • registry público registry.npmjs.org;
  • npm 12.0.2 em hoisted;
  • pnpm 11.24.0 em isolated — o dist-tag latest em 30/08/2026;
  • Yarn 4.18.0 em PnP e, como controle, em node-modules;
  • Bun 1.4.0 em hoisted, o padrão de um pacote único;
  • cinco instalações frias com lockfile presente, cache vazio e rede habilitada;
  • dez instalações quentes com cache aquecido, artefato removido e rede explicitamente desabilitada em cada CLI;
  • ordem em rotação: cada cenário ocupa cada posição uma vez no frio e duas no quente, reduzindo viés temporal;
  • scripts de lifecycle desativados igualmente para não transformar política de segurança em vantagem de tempo;
  • mediana, mínimo e máximo, nunca apenas a melhor execução; com cinco ou dez amostras, chamar o máximo de p95 daria precisão estatística falsa;
  • ao final, cada cenário tenta compilar a API e executar um teste HTTP real com Node.js.

Resultado

Cenário Fria: mediana / máximo Quente offline: mediana / máximo Projeto Cache ao final Build + teste em Node
npm 12 hoisted 2,005 s / 2,642 s 1,538 s / 1,632 s 151,5 MiB 197,7 MiB passou
pnpm 11 isolated 2,715 s / 4,429 s 1,327 s / 1,417 s 151,3 MiB 144,3 MiB passou
Yarn 4 PnP 2,109 s / 2,666 s 0,555 s / 0,717 s 76,9 MiB 145,3 MiB falhou no TypeScript 7
Yarn 4 node-modules 3,730 s / 5,301 s 1,473 s / 2,058 s 157,6 MiB 145,3 MiB passou
Bun 1.4 hoisted 1,338 s / 1,529 s 0,194 s / 0,373 s 151,3 MiB 162,8 MiB passou

Não leia a tabela como campeonato universal. O teste frio inclui a internet pública e teve apenas cinco amostras; seu máximo é sensível a qualquer oscilação. O quente isola melhor resolução e materialização, mas continua específico desta fixture, máquina e filesystem. A coluna de cache registra o estado ao final da décima rodada quente, não uma mediana.

Ainda assim, três conclusões são úteis:

  1. Bun foi o instalador mais rápido nesta fixture, tanto frio quanto quente. Isso não prova que a aplicação ficará mais rápida; ela continuou executando em Node.js.
  2. Yarn PnP teve instalação quente muito curta, mas TypeScript 7.0.2 não resolveu os módulos da fixture na compilação. yarn node encontrava os pacotes, enquanto tsc produzia TS2307. O mesmo Yarn 4.18.0, trocando apenas para nodeLinker: node-modules, compilou e testou normalmente.
  3. npm, pnpm, Yarn com node_modules e Bun passaram no build e no teste. As diferenças quentes entre os três primeiros ficaram bem menores que os gráficos promocionais costumam sugerir.

O dado de PnP não significa “Yarn está quebrado”. Significa exatamente o que foi observado: Yarn 4.18.0 + PnP + TypeScript 7.0.2, nesta fixture, exigiria outra investigação ou configuração antes de ser aprovado. Comparar o linker PnP e depois condenar o Yarn inteiro seria tão incorreto quanto ignorar a falha.

E o disco?

Medir somente node_modules produz números bonitos e conclusões ruins.

pnpm usa hardlinks para uma store compartilhada; Yarn PnP mantém arquivos compactados em cache e descompacta alguns pacotes; Bun e npm também têm caches. Por isso o resultado bruto registra separadamente o espaço alocado do projeto e do cache. Na fixture, os projetos com node_modules ficaram próximos de 151–158 MiB. O PnP ficou perto de 77 MiB no projeto porque dependências que precisam ser “unplugged” ainda ocupam espaço. As caches aquecidas ficaram entre cerca de 144 e 198 MiB.

Isso não mede a principal promessa do pnpm: reaproveitar a mesma store em vários projetos. Também não se deve somar cegamente projeto e cache: hardlinks e clone-on-write podem fazer duas travessias contarem os mesmos blocos físicos. Para provar economia total, seria preciso instalar a mesma árvore no primeiro, quinto e décimo checkout e deduplicar blocos por inode ou pelo mecanismo do filesystem. O artigo não chama uma hipótese de resultado.

Você pode baixar os dados, harness e fixture da bancada. O bundle inclui as 75 amostras, o resumo derivado, o ambiente sem identificação da máquina e todo o código necessário para repetir a medição.

[[codeinit-anchor:npm]]

npm: o padrão de menor atrito

npm é distribuído com Node.js e continua sendo o caminho com menos decisões adicionais. Sua vantagem mais consistente não é vencer todos os benchmarks; é ser conhecido por quase toda equipe Node, aparecer em praticamente todo tutorial e funcionar com a estrutura que ferramentas antigas esperam.

Como instala

O padrão é uma árvore node_modules hoisted. Dependências compartilháveis sobem para níveis superiores; versões incompatíveis permanecem aninhadas. Isso reduz duplicação e melhora compatibilidade, mas pode expor uma dependência transitiva a um pacote que nunca a declarou.

Imagine que sua aplicação importa chalk sem listar chalk no próprio package.json. Outra biblioteca trouxe o pacote, o hoisting o colocou no topo e o import “funciona”. Ao atualizar a árvore ou mudar de gerenciador, ele some. O bug não nasceu na migração; a migração revelou uma phantom dependency.

npm atual também oferece estratégias nested, shallow e linked. Portanto, “npm sempre cria uma árvore plana” já é uma simplificação. O padrão continua hoisted, mas autores de bibliotecas podem usar uma instalação mais estrita para detectar imports não declarados. Veja a referência oficial de install.

Lockfile e CI

O lockfile é package-lock.json. No computador de desenvolvimento, npm install pode resolver mudanças e atualizar o arquivo. No CI, use:

npm ci

npm ci exige lockfile, falha se ele divergir do package.json, remove um node_modules existente e não reescreve os manifestos. Se o lockfile foi criado com flags que alteram a árvore, como legacy-peer-deps, grave essa decisão no .npmrc versionado em vez de escondê-la no notebook de alguém. A documentação completa está em npm ci.

Quando escolher npm

  • projeto simples ou médio sem dor operacional relevante;
  • equipe que quer onboarding imediato;
  • ferramentas que pressupõem layout hoisted;
  • workspaces pequenos que não exigem filtros sofisticados;
  • organização em que familiaridade vale mais que otimizar segundos.

Onde prestar atenção

  • dependências fantasmas no layout padrão;
  • cópias separadas entre muitos projetos;
  • scripts e configurações de instalação precisam de política explícita;
  • npm install não substitui npm ci num pipeline reproduzível.

[[codeinit-anchor:pnpm]]

pnpm: store compartilhada e dependências mais disciplinadas

pnpm muda a forma de armazenar e ligar pacotes. Os arquivos entram numa store endereçada por conteúdo; o projeto recebe hardlinks para essa store e symlinks que representam as relações da árvore. A estrutura intermediária fica em node_modules/.pnpm.

A documentação de motivação e a explicação da estrutura de links mostram a arquitetura sem depender de slogans.

O que isso resolve

Quando vários checkouts usam o mesmo pacote, a store pode reaproveitar seus arquivos. Dependências diretas continuam acessíveis; transitivas não ficam todas expostas na raiz. Em monorepos, --filter, comandos recursivos e o protocolo workspace: tornam relações locais explícitas.

Isso não significa isolamento absoluto por padrão. pnpm faz algum hoisting em node_modules/.pnpm/node_modules para compatibilidade com pacotes quebrados. A rigidez depende da configuração. A frase correta é “mais disciplinado que um layout completamente plano”, não “phantom dependency é impossível”.

Workspaces e CI

O workspace raiz usa pnpm-workspace.yaml:

packages:
  - "apps/*"
  - "packages/*"

E uma dependência interna pode exigir o pacote local:

{
  "dependencies": {
    "@minha-org/utils": "workspace:^"
  }
}

Se a versão local não satisfaz a declaração, a instalação falha em vez de buscar silenciosamente outro pacote no registry. No CI, deixe a intenção explícita:

pnpm install --frozen-lockfile

Qual pnpm usar em 2026?

Quando a bancada foi executada, pnpm 11.24.0 era o latest e a linha 12 estava no canal de próxima versão. Em 7 de setembro de 2026, pnpm 12.3.4 já era o latest. Por isso o resultado acima continua identificado como pnpm 11 e não é apresentado como benchmark do pnpm 12.

Num projeto novo, avalie a major atual. Numa migração, compare a versão hoje usada e a major pretendida no seu CI, com o mesmo lockfile importado, build, testes e rollback. Se você testar primeiro o pnpm 11 para separar variáveis, trate-o como baseline temporário — não como prova de que a linha anterior é a melhor escolha.

Quando escolher pnpm

  • muitos projetos compartilham dependências na mesma máquina ou runner;
  • o repositório é um monorepo;
  • filtros e execução seletiva fazem parte do dia a dia;
  • dependências não declaradas já causaram problema;
  • a equipe aceita symlinks e configuração de workspace.

Onde prestar atenção

  • tooling que percorre node_modules manualmente;
  • plataformas ou empacotadores com suporte ruim a symlinks;
  • medir disco sem incluir a store;
  • aprovar conscientemente pacotes que precisam de scripts de build.

Se a escolha for migrar, siga o processo com baseline, validação e rollback descrito mais adiante.

[[codeinit-anchor:yarn-moderno]]

Yarn Classic e Yarn moderno não são a mesma coisa

“Yarn” é o nome mais perigoso desta comparação. A linha Classic 1.x e o Yarn moderno, iniciado no 2, compartilham marca e lockfile, mas não devem ser tratados como a mesma geração de ferramenta.

Yarn Classic usa node_modules, hoisting tradicional e o conhecido:

yarn install --frozen-lockfile

A linha 1 entrou em manutenção em 2020. Isso não obriga um projeto legado e estável a migrar amanhã, mas não a torna uma escolha inicial forte para projetos novos. O pacote yarn instalado globalmente pelo npm continua associado à linha Classic; para Yarn 4, siga a instalação oficial.

Yarn moderno e seus três linkers

Yarn moderno usa PnP por padrão. Em vez de uma árvore node_modules, ele gera um mapa, normalmente .pnp.cjs, que sabe onde cada pacote está e qual dependência pode acessar.

PnP não é obrigatório. A documentação de linkers lista três opções estáveis:

  • pnp: loader sem node_modules tradicional;
  • pnpm: store e links em modelo semelhante ao pnpm;
  • node-modules: layout convencional.

Essa distinção explicou a principal surpresa da bancada. O Yarn 4 resolveu e instalou a árvore em PnP, e yarn node encontrava fastify. Mas o TypeScript 7.0.2 não encontrou as declarações ao executar a compilação. Ao trocar apenas o linker para node-modules, a mesma versão do Yarn passou.

Num projeto real, o próximo passo seria investigar a compatibilidade entre essa versão do TypeScript, o loader PnP e a configuração do projeto. Os SDKs do Yarn ajudam a integração do editor, mas esta bancada não demonstrou que corrigiriam o tsc da CLI. O passo errado seria publicar “o Yarn não funciona” ou desligar PnP sem entender o requisito.

Por que usar Yarn moderno

PnP detecta acessos de dependência de maneira semântica. Constraints conseguem impor regras sobre versões e campos de manifestos em todos os workspaces. workspaces focus cria instalações focadas; workspaces foreach executa tarefas em vários pacotes. Cache versionado e PnP permitem Zero-Installs em cenários controlados.

No CI, o comando atual é:

yarn install --immutable

--frozen-lockfile ainda aparece em tutoriais, mas no Yarn moderno é um alias de compatibilidade com remoção futura. Para cache versionado e pull requests não confiáveis, avalie também --immutable-cache e --check-cache, conforme a referência de install.

Quando escolher Yarn moderno

  • PnP é um requisito, não curiosidade;
  • o monorepo precisa de Constraints;
  • Zero-Installs tem benefício mensurável;
  • a organização quer plugins e políticas próprias;
  • a equipe já usa Yarn e quer evoluir com cuidado.

Onde prestar atenção

  • IDE, TypeScript e ferramentas podem exigir integração específica com PnP;
  • mais poder de configuração exige mais padronização;
  • guias de Yarn Classic ainda aparecem como se fossem atuais;
  • migrar da CLI e adotar PnP ao mesmo tempo dificulta isolar falhas.

Uma migração conservadora de Yarn 1 pode primeiro levar o projeto ao Yarn moderno com nodeLinker: node-modules. Depois que CLI, lockfile e CI estiverem estáveis, a equipe avalia PnP separadamente.

[[codeinit-anchor:bun]]

Bun: package manager e runtime são decisões separadas

Bun reúne runtime, package manager, test runner e bundler. Neste artigo, a comparação principal mede apenas o instalador. Este fluxo é válido:

bun install
node src/index.js

Bun resolveu as dependências; Node executou a aplicação. Para avaliar o runtime, crie uma segunda matriz:

bun run src/index.ts

Se você troca instalador e runtime no mesmo pull request, uma falha pode vir do lockfile, do linker, da política de scripts ou de uma API incompatível. Separar as mudanças é uma técnica de diagnóstico, não burocracia.

Cache, linkers e lockfile

Bun usa cache global e pode materializar pacotes por clonefile no macOS, hardlinks em outros sistemas ou cópia como fallback. Oferece os linkers hoisted e isolated. Pacote único novo tende ao hoisted; workspaces novos usam isolated conforme a configuração atual. Veja a documentação de isolated installs.

O lockfile atual é textual e se chama bun.lock. O antigo bun.lockb era binário. Bun consegue importar formatos suportados de npm, Yarn Classic e pnpm, mas preservar o lockfile antigo durante a revisão não significa manter dois para sempre. A documentação do lockfile recomenda versionar bun.lock.

No CI:

test -f bun.lock
bun ci

O teste explícito de existência evita um pipeline “reproduzível” sem fonte de verdade. bun ci equivale à instalação frozen.

O resultado da bancada

Bun foi o mais rápido nesta fixture e passou no build e no teste executados com Node. Essa frase contém três limites importantes: nesta fixture, nesta máquina e com Node como runtime. Ela não permite afirmar que Bun será o mais rápido no seu CI nem que sua aplicação rodará melhor em Bun.

Quando escolher Bun

  • a equipe já pretende avaliar ou adotar o runtime Bun;
  • uma toolchain integrada reduz uma dor real;
  • o projeto novo comporta um piloto e rollback;
  • dependências nativas, peers, scripts e deploy passaram na matriz;
  • velocidade de instalação foi medida no ambiente da organização.

Onde prestar atenção

  • package manager e runtime têm superfícies de compatibilidade diferentes;
  • lifecycle scripts usam uma allowlist própria;
  • Corepack não gerencia Bun;
  • addons nativos e tooling que inspeciona node_modules precisam de prova;
  • o lockfile textual atual não deve ser confundido com bun.lockb de artigos antigos.

[[codeinit-anchor:comparacao-lado-a-lado]]

Comparação lado a lado

Critério npm 12 pnpm 12 Yarn 4 Bun 1.4
layout padrão hoisted isolated com store e links PnP hoisted em pacote único
linkers alternativos nested, shallow, linked hoisted e ajustes PnP, pnpm, node-modules hoisted, isolated
lockfile package-lock.json pnpm-lock.yaml yarn.lock bun.lock
CI imutável npm ci pnpm i --frozen-lockfile yarn install --immutable bun ci
workspace campo workspaces pnpm-workspace.yaml campo workspaces campo workspaces
filtro/foco --workspace --filter workspaces focus/foreach --filter, --workspaces
Corepack reconhecido reconhecido reconhecido não suportado
principal força compatibilidade store, filtros, disciplina PnP e governança velocidade e integração
principal custo hoisting esconde imports links quebram tooling ruim configuração e integração maturidade e dupla decisão

Esta tabela descreve as linhas atuais. A bancada anterior executou pnpm 11.24.0 e Bun 1.4.0; nenhum tempo medido foi transferido para pnpm 12.3.4 ou Bun 1.4.2.

[[codeinit-anchor:lockfiles-e-instalacao-imutavel]]

Lockfile: a parte mais importante não aparece no ranking

package.json declara uma faixa aceitável; o lockfile registra a resolução concreta de dependências diretas e transitivas. Para reprodução, os dois precisam estar sincronizados e a CLI precisa se recusar a reescrever a decisão no CI.

Gerenciador Desenvolvimento CI imutável
npm npm install npm ci
pnpm pnpm install pnpm install --frozen-lockfile
Yarn moderno yarn install yarn install --immutable
Bun bun install bun ci

Não mantenha package-lock.json, pnpm-lock.yaml, yarn.lock e bun.lock para “cada pessoa escolher o seu”. Gerenciadores podem resolver peers, hoisting, metadata e scripts de maneiras distintas. Quatro lockfiles não dão quatro opções; dão quatro fontes de verdade concorrentes.

Durante uma migração, dois arquivos podem coexistir na branch para facilitar o diff e o rollback. Depois da validação, escolha um. Faça o CI falhar se o canônico estiver ausente ou se outro aparecer. A tabela acima resume o comando imutável dos quatro; a regra operacional é manter uma única fonte de verdade no CI.

Fixe também a versão da ferramenta

O lockfile não fixa a versão do package manager que o interpreta. Para npm, Yarn e pnpm, o campo packageManager registra uma versão exata:

{
  "packageManager": "pnpm@12.3.4"
}

Corepack consegue ler esse campo, mas deixou de ser distribuído com Node a partir do Node 25. Mesmo quando instalado, seus shims de npm não são habilitados por padrão como os de Yarn e pnpm. Em Node 26, instale Corepack separadamente ou use o mecanismo oficial da ferramenta. Em Docker e CI, fixe também a versão do Corepack ou o instalador escolhido — não dependa do estado global da imagem.

Bun não é suportado pelo Corepack. Fixe sua versão no instalador do CI e no tool manager adotado pela equipe.

[[codeinit-anchor:workspaces]]

Workspaces não são orquestradores

Os quatro suportam workspaces: ligam pacotes locais, entendem o repositório e executam comandos por workspace. Isso não adiciona automaticamente cache remoto, grafo incremental, distribuição de tarefas ou detecção avançada de projetos afetados.

npm workspaces atende bem muitos monorepos pequenos. pnpm tem filtros expressivos e o protocolo workspace:. Yarn adiciona Constraints, foco e execução topológica. Bun também possui filtros e catálogos. Se o gargalo é build, talvez a decisão correta seja adicionar Nx ou Turborepo, não migrar o package manager.

A bancada deste artigo usa um único pacote: ela não mediu filtros, workspaces nem cache entre vários checkouts. As recomendações de monorepo nesta seção derivam da arquitetura e da documentação das ferramentas e ainda precisam de prova no repositório real.

[[codeinit-anchor:seguranca]]

Segurança: quem pode executar código durante a instalação?

Lockfile reduz drift; não certifica que um pacote é seguro. Uma versão maliciosa pode já estar fixada, uma conta de publicação pode ser roubada e um postinstall pode executar código antes de qualquer teste.

Em 2026, os quatro endureceram essa área, mas com modelos diferentes:

Não conclua “desative todos os scripts”. esbuild, drivers e addons nativos podem precisar compilar ou baixar binários. O fluxo seguro é bloquear o desconhecido, ver o que foi impedido, revisar finalidade e origem e versionar apenas as aprovações necessárias.

Age gates também seguram versões recém-publicadas por um intervalo antes de uma nova resolução. Eles não removem uma versão que já está no lockfile. Auditoria, revisão de diffs, integridade, registry confiável e atualização deliberada continuam necessárias.

[[codeinit-anchor:migracao]]

Como migrar sem transformar a produção em teste A/B

Uma migração segura começa antes de apagar qualquer arquivo.

1. Registre o baseline

node --version
npm --version
npm ci
npm test
npm run typecheck
npm run build
npm pack --dry-run

Adapte ao projeto e registre tempo de CI, cache, warnings de peers, addons nativos e scripts de instalação. Se o baseline já falha, documente antes; caso contrário você atribuirá ao gerenciador novo um bug antigo.

2. Declare a hipótese

“pnpm parece melhor” não é critério de sucesso. “Reduzir a mediana da instalação de 90 para menos de 45 segundos sem alterar o tarball nem quebrar Linux e macOS” é uma hipótese testável.

3. Importe sem apagar o rollback

pnpm oferece pnpm import; Bun importa formatos suportados quando não existe bun.lock; a migração do Yarn Classic tem guia próprio. Preserve o lockfile antigo durante a revisão. Importação ajuda, mas não prova equivalência de peers, scripts e layout.

4. Troque toda a infraestrutura na mesma mudança

Atualize lockfile, pin da CLI, CI, Dockerfile, cache keys, release, Renovate ou Dependabot, plataformas de deploy e onboarding. Deixar metade no npm e metade no pnpm cria um estado mais perigoso que qualquer uma das opções sozinha.

5. Valide numa cópia limpa

Rode test, typecheck, build, pack, imagem de produção e staging. Teste os sistemas operacionais reais e qualquer addon nativo. Compare o conteúdo publicado, não apenas o exit code.

6. Remova o antigo e mantenha rollback

Depois da aprovação, deixe um único lockfile no branch principal. Concentre a migração num PR que possa ser revertido sem desfazer features não relacionadas.

[[codeinit-anchor:quando-nao-migrar]]

Quando não migrar

Não migre apenas porque:

  • o site de um fornecedor publicou um gráfico grande;
  • a ferramenta está popular nas redes;
  • node_modules parece enorme sem medir cache e store;
  • outro time usa uma opção diferente;
  • o verdadeiro gargalo está em build, teste ou imagem Docker;
  • faltam capacidade de validação e janela de rollback.

Também adie durante release crítica, antes de testar addons nativos ou quando CI e desenvolvimento não podem mudar juntos. Infraestrutura boa reduz tempo e incerteza da equipe; novidade não é requisito.

[[codeinit-anchor:cenarios]]

Veredito por cenário

Projeto pessoal ou API pequena

Comece com npm. Se aparecer uma dor concreta, reabra a decisão. Um projeto pequeno não precisa de infraestrutura sofisticada para parecer moderno.

Startup com vários serviços

pnpm é um ótimo candidato. A store e a disciplina se tornam mais valiosas quando o número de checkouts cresce. Meça no runner da empresa, incluindo store e cache.

Monorepo de aplicações e bibliotecas

Avalie pnpm e Yarn moderno. pnpm favorece fluxo baseado em node_modules, store e filtros. Yarn ganha quando PnP, Constraints ou Zero-Installs são requisitos. npm continua suficiente para muitos repositórios menores.

Biblioteca publicada no npm

O risco principal é publicar um pacote que importa algo não declarado. Teste uma instalação estrita, execute pack e instale o tarball num consumidor limpo. O gerenciador do monorepo não controla a instalação de quem consome a biblioteca.

Projeto legado

Mantenha o atual até existir uma justificativa forte. Se usa Yarn Classic, separe migração da CLI e adoção de PnP. Se o tooling exige hoisted, registre isso como requisito em vez de tratar como vergonha técnica.

Projeto que adotará o runtime Bun

Teste Bun como package manager, depois como runtime. Se as duas mudanças entram juntas, mantenha uma matriz que diga qual combinação falhou.

Equipe grande com governança

Yarn Constraints e políticas do pnpm merecem avaliação. A decisão deve incluir registry corporativo, age gate, scripts permitidos, atualização automatizada, auditoria e lockfile imutável — não apenas ergonomia local.

[[codeinit-anchor:veredito-final]]

O veredito final

Não existe “o melhor package manager Node.js” fora de contexto.

  • npm vence quando o objetivo é começar e operar com o menor atrito.
  • pnpm é a escolha mais equilibrada para muitos times e monorepos.
  • Yarn moderno entrega o modelo mais especializado para PnP e governança.
  • Bun mostrou velocidade excelente na bancada e merece um piloto quando a equipe aceita validar sua compatibilidade e sua estratégia de runtime.

No teste CodeInit, Bun instalou mais rápido; Yarn PnP foi rápido no cache quente, mas falhou na compilação com TypeScript 7; o linker node-modules do próprio Yarn passou. Esse resultado reforça a tese do artigo: arquitetura, compatibilidade e custo de mudança valem mais que um pódio isolado.

Para um repositório existente, comece pelo lockfile que já existe. Migre somente com dor mensurável, hipótese clara, prova reproduzível e rollback.

[[codeinit-anchor:perguntas-frequentes]]

Perguntas frequentes

pnpm é melhor que npm?

Não em todos os projetos. pnpm oferece store compartilhada, filtros fortes e uma estrutura menos plana. npm reduz custo de adoção e maximiza compatibilidade. Em monorepos e muitos checkouts, pnpm costuma ter mais a oferecer; numa API simples, npm pode ser a escolha mais econômica.

pnpm é sempre mais rápido?

Não. Na fixture CodeInit, a mediana quente do pnpm ficou um pouco abaixo do npm, mas o máximo variou e a instalação fria não foi menor. Cache, rede, filesystem e árvore mudam o resultado. Meça seu projeto.

Yarn ainda vale a pena em 2026?

Yarn moderno, sim, especialmente por PnP, Constraints, workspaces e Zero-Installs. Yarn Classic 1.x está em manutenção e não seria a escolha inicial para projeto novo.

Yarn moderno exige PnP?

Não. PnP é o padrão, mas os linkers node-modules e pnpm também são estáveis. O próprio benchmark deste artigo usou PnP e node-modules separadamente.

Posso usar Bun para instalar e Node para executar?

Sim. Foi exatamente a validação da bancada: Bun instalou, TypeScript compilou e Node executou os testes. Isso não prova compatibilidade com o runtime Bun; ela precisa de outra matriz.

Usar bun install deixa minha API mais rápida?

Não. Tempo de instalação e desempenho em produção são métricas diferentes. O primeiro afeta setup e pipeline; o segundo depende de runtime, código e carga.

Qual usa menos disco?

Depende de quantos projetos compartilham cache/store e de como o filesystem conta hardlinks. Meça projeto, cache e store separadamente. Não some os valores como se fossem blocos físicos únicos: hardlinks e clone-on-write podem produzir contagem duplicada. Um total exige protocolo que deduplique inode/bloco no filesystem usado.

Posso versionar dois lockfiles?

Temporariamente numa migração, sim. Como estado permanente, não. Dois lockfiles permitem resoluções diferentes e fazem deploy, bots e pessoas escolherem fontes de verdade concorrentes.

Devo versionar lockfile numa biblioteca?

Sim, para reproduzir desenvolvimento e CI. Ele normalmente não determina as versões instaladas por quem consome o pacote publicado, mas continua protegendo o repositório da biblioteca.

Corepack ainda vem com Node?

Não a partir do Node 25. Ele continua disponível separadamente e pode selecionar npm, Yarn ou pnpm pelo campo packageManager, embora os shims de npm não sejam ativados por padrão. Corepack não gerencia Bun.

Qual é o equivalente a npm ci?

  • pnpm: pnpm install --frozen-lockfile;
  • Yarn moderno: yarn install --immutable;
  • Bun: bun ci.

Bloquear postinstall pode quebrar pacotes?

Pode. Alguns pacotes compilam ou baixam binários na instalação. A solução é revisar e aprovar apenas os necessários, não liberar todos nem ignorar a falha.

Qual é o mais seguro?

Nenhum sozinho. Os quatro têm mecanismos úteis, mas segurança depende de lockfile revisado, integridade, scripts controlados, atualização deliberada, auditoria, registry confiável e CI imutável.

Newsletter

Receba os artigos novos por e-mail

Sem spam. Só o aviso quando sai um tutorial ou artigo novo.