12k
All articles

Por dentro da reescrita do pnpm em Rust

Veja a reescrita do pnpm 12 em Rust, os resultados de desempenho, a compatibilidade com pnpm 11 e os riscos de atualização que podem afetar a CI.

OpenReplay Team
OpenReplay Team
Por dentro da reescrita do pnpm em Rust

O pnpm 12 substitui a base de código em TypeScript do pnpm por uma reescrita nativa em Rust e mantém os comandos, flags, configurações e o formato de lockfile do pnpm 11. Com isso, a maioria dos projetos pode atualizar sem editar nenhuma configuração.

Se você usa o pnpm em um monorepo e em uma frota de CI movimentada, provavelmente já viu “90% mais rápido” nas manchetes e quis saber qual é o porém. Uma nova versão major da ferramenta que escreve o seu lockfile merece mais escrutínio do que um gráfico de benchmark.

Este artigo explica por que um gerenciador de pacotes em JavaScript é lento, o que o engine em Rust mudou e quanto isso custou, quem mediu cada número e quais mudanças de comportamento podem afetar o seu pipeline.

Principais conclusões

  • O pnpm 12.0.0 foi lançado como estável em 26 de agosto de 2026. Ele mantém os comandos, flags, configurações e o formato de lockfile do pnpm 11, exceto por uma lista curta de diferenças documentadas.
  • Na página de benchmarks do próprio pnpm (pnpm 11.27.1 vs. 12.7.0), uma instalação repetida com cache quente cai de 563 ms para 18 ms. Já uma instalação limpa cai apenas de 8,4 s para 4,4 s, porque a transferência pela rede e a descompactação dominam as instalações a frio.
  • A Vercel mediu que seu workspace de 1.670 pacotes instala em 64,4% a 90,5% menos tempo no pnpm 12 do que no pnpm 10.28. Em contrapartida, a inicialização do Corepack sem cache ficou 11,1% mais lenta, porque o download nativo é maior.
  • A mudança com maior chance de quebrar o CI é a remoção de pnpm install --resolution-only. Use pnpm peers check no lugar.

A restrição: o mesmo pnpm, outro engine

O pnpm 12 foi construído para que a atualização não parecesse uma migração. O post de lançamento do pnpm 12.0 define esse objetivo, e o guia de compatibilidade confirma que, exceto por uma lista curta de diferenças, o pnpm 12 mantém os comandos, flags, configurações e o formato de lockfile do pnpm 11. O pnpm 12 também mantém o store endereçável por conteúdo, que permite que projetos compartilhem os arquivos dos pacotes em vez de copiá-los. A InfoQ também aponta que o layout do node_modules não mudou.

A maioria das reescritas trata a nova base de código como uma oportunidade para corrigir decisões de design antigas. O pnpm fez da compatibilidade o objetivo, a ponto de afirmar que sua documentação vale para as duas versões. Quase nada mudou na superfície. O trabalho foi substituir tudo o que fica por baixo dela.

Por que um gerenciador de pacotes em JavaScript é lento?

Um gerenciador de pacotes escrito em JavaScript paga dois custos em toda instalação grande. Ele inicializa o runtime do Node.js a cada invocação e faz milhares de operações de sistema de arquivos passarem por um único runtime JavaScript.

Uma instalação passa, de forma geral, por estas fases:

  1. Buscar os metadados dos pacotes no registry.
  2. Resolver o grafo de dependências.
  3. Baixar os tarballs.
  4. Descompactá-los no store.
  5. Vincular os pacotes no node_modules.

O primeiro custo é fixo. Antes que o pnpm 11 fizesse qualquer trabalho de fato, o Node.js precisava iniciar. O pnpm 12 é publicado como binários nativos, com um pacote @pnpm/exe.<platform>-<arch> por plataforma. A documentação do self-update confirma que nada inicia o Node.js antes, então esse custo de inicialização desaparece.

O segundo custo cresce com o volume de trabalho. As fases 4 e 5 envolvem descompactar tarballs e criar hard links para milhares de arquivos, e cada uma dessas operações passa pelo runtime JavaScript.

O princípio vale para qualquer ferramenta: remover um overhead fixo ajuda mais quando sobra pouco trabalho além dele. Quando uma instalação quase não tem o que fazer, a inicialização representa a maior parte do tempo total decorrido. Quando ela precisa baixar centenas de megabytes, a inicialização mal aparece.

Quanto mais rápido é o pnpm 12?

Os ganhos de velocidade do pnpm 12 são reais, mas desiguais: uma instalação repetida com cache quente cai de 563 ms para 18 ms, enquanto uma instalação limpa cai apenas de 8,4 s para 4,4 s. Os ganhos vêm de dois conjuntos de medições distintos, com baselines diferentes. Não os combine em um único número.

CenárioAntespnpm 12Medido porBaseline
Instalação repetida com cache quente563 ms18 msPágina de benchmarks do pnpm (pnpm 12.7.0)pnpm 11.27.1
Instalação limpa8,43 s4,42 sPágina de benchmarks do pnpm (pnpm 12.7.0)pnpm 11.27.1
Workspace de 1.670 pacotes, seis cenários (mediana)n/d64,4–90,5% menos tempoVercel (pnpm 12.0.0)pnpm 10.28.0
Inicialização do Corepack sem cachen/d11,1% mais lentaVercel (pnpm 12.0.0)pnpm 10.28.0
Inicialização do Corepack com cachen/d74,7% mais rápidaVercel (pnpm 12.0.0)pnpm 10.28.0

Os números do pnpm se referem ao projeto alotta-files na página de benchmarks do pnpm, comparando o pnpm 11.27.1 com o pnpm 12.7.0. A página é reexecutada regularmente e sempre mostra a versão mais recente de cada ferramenta, então espere que esses números mudem. A diferença entre as duas linhas do pnpm é a seção anterior na prática. A instalação com cache quente melhora cerca de 30x, provavelmente porque custos fixos, como a inicialização, representavam uma grande parte do seu tempo de execução. A instalação limpa melhora cerca de 1,9x porque a transferência pela rede e a descompactação dos tarballs ocupam a maior parte do tempo, seja qual for a linguagem em que o engine foi escrito.

As próprias medições da Vercel mostram o mesmo padrão. Com o node_modules já presente, o store aquecido e os scripts desativados, as instalações caíram de 1,476 s para 142 ms. Uma instalação totalmente a frio, com lifecycle scripts habilitados, foi de 9,850 s para 3,472 s. Cada mediana vem de 20 execuções por versão em uma única máquina Linux, em um workspace Turborepo com 21 projetos.

O build nativo do pnpm 12 tem um custo. A Vercel registrou o download do pnpm 12 pelo Corepack em 47,3 MB, contra 17,5 MB do pnpm 10.28.0, e atribui a inicialização mais lenta sem cache a esse download maior. Runners de CI que não fazem cache do Corepack provavelmente pagarão esse custo em todos os jobs.

O tratamento determinístico de ciclos, lançado junto com o engine, é um ganho à parte. O guia de compatibilidade do pnpm atribui a essa mudança, e não ao engine em Rust em si, um uso de memória cerca de 25% menor e uma resolução de peer dependencies de 2 a 3x mais rápida em workspaces com muitos ciclos.

A página pública de benchmarks do pnpm agora compara o pnpm 12 apenas com o npm e o pnpm 11. A InfoQ informou que o pnpm removeu o Bun e o Yarn da comparação depois que problemas na configuração do benchmark tornaram esses rankings pouco confiáveis.

Por que o formato do lockfile do pnpm precisou permanecer idêntico?

O formato do lockfile do pnpm 12 precisou permanecer o mesmo porque uma quebra no lockfile dividiria a equipe no meio da atualização. Se o pnpm 12 gravasse um novo formato, todos os notebooks e runners de CI teriam de migrar no mesmo dia. Caso contrário, dois dialetos de lockfile disputariam o mesmo repositório, e cada pull request carregaria ruído da última versão que foi executada.

Manter o formato serve para permitir que a equipe atualize de forma gradual. Isso não significa que nada no arquivo vá mudar. Formato e conteúdo são coisas diferentes:

  • Lockfiles existentes continuam funcionando. O guia observa que o pnpm não altera as entradas existentes até que algo o obrigue a resolvê-las novamente.
  • A re-resolução pode alterar entradas. O pnpm 12 registra dependências do GitHub, GitLab e Bitbucket pela URL HTTPS, nunca por SSH. Ele também corta os ciclos de dependência sempre no mesmo ponto, o que deixa os lockfiles menores em workspaces com muitos ciclos.

Revise o diff da sua primeira instalação com re-resolução no pnpm 12 em um commit separado.

O que quebra ao atualizar para o pnpm 12?

Se a atualização para o pnpm 12 quebrar um job de CI, a causa mais provável é um script que ainda chama pnpm install --resolution-only. A v12 rejeita essa flag. A função de reportar peer dependencies agora pertence ao pnpm peers check:

# pnpm 11
pnpm install --resolution-only

# pnpm 12
pnpm peers check

A v12 também rejeita pnpm install --frozen-lockfile false. Use --no-frozen-lockfile para desativar o modo frozen-lockfile e --frozen-lockfile sozinho para ativá-lo.

As demais mudanças afetam principalmente os resultados, mas três delas também podem interromper um comando:

MudançaQuem é afetadoO que fazer
Dependências Git do GitHub/GitLab/Bitbucket são resolvidas via HTTPSRepositórios privados acessados por SSHConfigurar a reescrita de URLs do Git na máquina
Chaves desconhecidas no pnpm-workspace.yaml são reportadas e fazem o comando falhar com ERR_PNPM_UNRECOGNIZED_WORKSPACE_SETTINGS quando o projeto fixa uma versão do pnpm atendida pelo pnpm em execuçãoConfigurações com erros de digitaçãoCorrigir ou remover a chave
Comandos que alteram a instalação global falham sob sudo com ERR_PNPM_SUDO_NOT_SUPPORTEDsudo pnpm self-update e similaresExecutá-los sem sudo
Com engineStrict ativado, um engine incompatível em dependencies comuns faz a instalação falhar, mesmo com uma entrada em optionalDependenciesProjetos que usam engineStrictEsperar que instalações que antes geravam aviso agora falhem
No Linux, packageImportMethod: auto tenta hardlinks antes de reflinksUsuários de LinuxNormalmente, nada
node, deno ou bun globais seguem a versão fixada no projetoMáquinas com runtimes globaisEsperar a versão fixada

As notas de lançamento da v12.0.0 explicam por que a verificação do workspace é importante. No pnpm 11, um erro de digitação em uma configuração como minimumReleaseAge fazia o pnpm ignorar a chave silenciosamente, de modo que a regra que ela deveria definir nunca era aplicada:

# pnpm-workspace.yaml
packages:
  - "apps/*"
minimumReleseAge:   # typo: pnpm 12 reports this key

O guia de compatibilidade lista oito diferenças no total. Seis alteram um resultado e duas rejeitam sintaxes de linha de comando que o pnpm 11 aceitava: --resolution-only e --frozen-lockfile false. A tabela acima não cobre todas elas. Ela deixa de fora como o pnpm 12 trata nomes de gerenciadores de pacotes, como yarn, em pnpm add, e as linhas sobre chaves do workspace e sudo vêm das notas de lançamento, e não do guia. Leia o guia completo antes de atualizar.

Vale a pena atualizar para o pnpm 12?

Normalmente sim, e a atualização acontece sem sustos. Esse era o objetivo do design. A partir do pnpm 11.10 ou mais recente, execute:

pnpm self-update

Em um projeto que fixa o pnpm via packageManager, o self-update apenas atualiza a versão nesse campo, em vez de instalar o pnpm globalmente. O pnpm então baixa a nova versão na próxima vez que você executar um comando. Faça commit da alteração para que o CI use a mesma versão:

{
  "packageManager": "pnpm@12.8.1"
}

Use a versão 12.x mais recente. Se a sua instalação depende de recursos menos comuns, como pnpm deploy ou modos específicos de linker, teste a atualização primeiro em uma branch. Equipes que ainda usam o npm podem ler se vale a pena migrar do npm para o pnpm antes de encarar as duas mudanças ao mesmo tempo.

Conclusão

O pnpm 12 manteve as partes que você usa no dia a dia, incluindo os comandos, o formato do lockfile e o modelo de store, e reconstruiu o engine por trás delas. A reescrita valeu a pena porque dois custos limitavam a versão em JavaScript: a inicialização do Node.js a cada invocação e o I/O de arquivos canalizado por um único runtime. Antes de atualizar, procure --resolution-only e --frozen-lockfile false na configuração do seu CI, verifique se há dependências Git privadas acessadas por SSH e faça commit do primeiro lockfile re-resolvido separadamente, para poder revisar o diff.

Perguntas frequentes

O pnpm 12 precisa do Node.js instalado para rodar?

Não. Depois de instalado, o pnpm 12 roda como um programa nativo, então o Node.js não é necessário. O script de instalação standalone também não precisa do Node.js, nem mesmo durante a instalação. A única exceção é instalar o pnpm 12 via npm, caso em que o instalador exige o Node.js 22.13 ou mais recente. Se a sua plataforma não tiver um binário pré-compilado do pnpm 12, a documentação do pnpm sugere usar o pnpm 11 em JavaScript.

Como continuo usando SSH para dependências Git privadas no pnpm 12?

O pnpm 12 busca dependências do GitHub, GitLab e Bitbucket pela URL HTTPS de cada host. Para continuar usando SSH, configure uma reescrita de URL do Git, por exemplo com git config --global url.'git@github.com:'.insteadOf https://github.com/. O pnpm chama o git internamente, então essa regra vale para todos os comandos Git que o pnpm executa. Hosts que o pnpm não reconhece e URLs que incluem credenciais são mantidos exatamente como você os escreveu, inclusive com SSH.

Por que o pnpm 12 falha com uma configuração não reconhecida no pnpm-workspace.yaml?

Ele só falha quando o projeto fixa uma versão do pnpm e o pnpm em execução corresponde a essa versão. Nesse caso, o pnpm trata a chave desconhecida como um erro e para com ERR_PNPM_UNRECOGNIZED_WORKSPACE_SETTINGS. Sem uma versão fixada correspondente, você recebe um aviso e o comando continua. Se a chave parecer um erro de digitação, o pnpm indica a configuração que você provavelmente quis usar. Os comandos pnpm config continuam funcionando em um arquivo com uma chave inválida, então você pode usá-los para encontrá-la e corrigi-la.

Quais comandos do pnpm 12 falham quando executados com sudo?

Sob sudo, pnpm setup, pnpm self-update e todos os comandos que alteram a instalação global, como pnpm add --global, param com ERR_PNPM_SUDO_NOT_SUPPORTED. Versões anteriores gravavam silenciosamente no diretório home do root. Pacotes e configurações globais ficam no seu próprio diretório home, então nenhum desses comandos precisa de root. Comandos somente leitura, como pnpm bin --global, continuam funcionando sob sudo.

DevTools for the frontend

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.

Star on GitHub12k

We use cookies to improve your experience. By using our site, you accept cookies.