O pipeline termina antes dos testes porque npm ci encontrou um package.json diferente do package-lock.json. A reação mais comum é trocar o comando por npm install até o job ficar verde. Isso mascara a origem do problema: o CI acabou de descobrir que o repositório não descreve uma árvore de dependências única.

A regra prática é simples: use npm install para adicionar ou atualizar dependências durante o desenvolvimento. Use npm ci no CI quando o lockfile já foi revisado e deve ser restaurado sem alterações. Se os arquivos divergirem, corrija o manifesto e o lockfile na branch, em vez de deixar o pipeline escolher uma versão nova.

Esse comando de instalação é uma parte pequena, mas importante, do contrato de entrega. O guia de GitLab CI para Node.js cobre a estrutura geral de um pipeline. Aqui, o foco é a decisão que acontece antes do typecheck, dos testes e do build.

Diagrama compara npm install editando o package.json com npm ci verificando o lockfile em um pipeline de CI.

Resposta curta

  • Rode npm install quando estiver alterando dependências ou regenerando o lockfile.
  • Rode npm ci em jobs automatizados que devem instalar o estado já aprovado.
  • Commite package.json e package-lock.json juntos quando uma dependência mudar.
  • Se npm ci falhar, compare os dois arquivos antes de trocar o comando.
  • O lockfile ajuda na repetição, mas não substitui revisão de scripts, versões de Node e permissões do runner.

Quando usar npm install?

npm install é o comando de mudança. Ele instala dependências no projeto e pode atualizar o package-lock.json quando a faixa declarada no package.json não combina com o lockfile. A documentação do npm sobre npm install, consultada em 26 de outubro de 2026, descreve o manifesto como a fonte das faixas aceitáveis e o lockfile como o registro das versões resolvidas.

Isso torna npm install adequado para tarefas como:

  • adicionar uma dependência de produção ou desenvolvimento;
  • atualizar uma versão permitida pelo manifesto;
  • reconstruir o lockfile depois de uma alteração intencional;
  • testar uma mudança de configuração que altera a árvore de dependências.

Depois de rodar o comando, revise o diff. O arquivo de lock pode mudar mais do que a linha que você editou porque a resolução afeta dependências transitivas. Não trate esse diff como lixo gerado. Ele é a proposta concreta da árvore que o próximo ambiente deverá instalar.

Em desenvolvimento, também vale confirmar a versão de Node e npm usada pelo projeto. Uma equipe que gera o lockfile com uma configuração e instala com outra pode descobrir a diferença apenas no CI. Registre a versão em .nvmrc, package.json, mise.toml ou no mecanismo que o projeto já usa, mas não coloque uma versão inventada em uma receita só para parecer completa.

O guia sobre um AGENTS.md enxuto trata o comando de instalação como parte das instruções verificáveis do repositório. A mesma ideia serve para qualquer equipe: diga qual comando restaura dependências, qual comando altera a árvore e qual prova deve rodar depois.

Quando usar npm ci no CI?

npm ci é a escolha normal para um job automatizado que precisa restaurar o estado descrito no lockfile. Em 2026, a documentação do npm sobre npm ci, consultada em 26 de outubro, diz que o projeto precisa ter um package-lock.json ou npm-shrinkwrap.json, que o comando falha quando o lockfile não combina com o manifesto e que ele não escreve esses arquivos.

O comportamento é útil justamente porque é rígido. Se alguém alterou package.json e esqueceu de gerar ou commitar o lockfile, o job para antes de testar uma árvore diferente da que a mudança pretendia. Se já existe node_modules, o npm o remove antes da instalação. O job começa com uma instalação limpa, dentro do limite que o runner e os scripts do projeto permitem.

Use npm ci quando estas condições forem verdadeiras:

  1. o lockfile está versionado;
  2. package.json e package-lock.json foram gerados com intenção e estão sincronizados;
  3. o job sabe qual versão de Node deve usar;
  4. os flags que influenciaram a resolução estão registrados;
  5. o resultado será seguido por typecheck, testes ou build.

O guia de lockfiles do setup-node, consultado em 26 de outubro de 2026, recomenda commitar o lockfile e usar npm ci para projetos npm no CI. Isso é uma orientação de fluxo, não uma autorização para copiar qualquer configuração. O projeto ainda precisa definir sua versão de Node, seus scripts e seus requisitos de plataforma.

Um detalhe importante: npm ci não é um comando de reparo. Se ele acusa divergência, o resultado desejado é um erro que alguém corrige no repositório. Executar npm install dentro do job para fazer o erro desaparecer transforma uma verificação em uma etapa de mutação. O próximo job pode então testar uma árvore que não está registrada no commit.

O que acontece quando os arquivos divergem?

Considere um projeto que tem is-number@7.0.0 no lockfile. Se alguém muda o manifesto para ^6.0.0 sem rodar npm install, o CI não tem uma resposta segura que preserve os dois arquivos. npm ci deve recusar a instalação e pedir que a branch atualize o lockfile.

Verifiquei esse caso em uma fixture temporária em 26 de outubro de 2026, com Node v25.5.0 e npm 11.8.0. Primeiro instalei is-number@7.0.0 com versão exata. Depois alterei apenas a dependência no package.json para ^6.0.0 e rodei npm ci. O comando terminou com status 1 e informou que is-number@7.0.0 não satisfazia is-number@6.0.0.

O fluxo de correção foi este:

# Depois de editar package.json de propósito
npm install

# Revise e commite package.json e package-lock.json juntos
git diff -- package.json package-lock.json

# O CI restaura o novo estado aprovado
npm ci

Na mesma fixture, npm install atualizou o lockfile para 6.0.0. Uma nova execução de npm ci instalou essa versão. Esse resultado demonstra o contrato dos arquivos em um caso pequeno. Não é benchmark, não mede velocidade e não prova o comportamento de workspaces, dependências nativas ou todos os formatos de lockfile.

Se o erro aparecer em um merge request, não resolva apagando o lockfile automaticamente. Primeiro descubra qual mudança deixou os arquivos fora de sincronia. A correção pode ser regenerar o lockfile com a versão de npm do projeto, ajustar a faixa no manifesto ou recuperar uma alteração que deveria ter sido incluída no mesmo commit.

Como escrever o passo de instalação no pipeline?

O passo deve mostrar a fronteira: configurar o runtime, instalar o que o commit declara e executar provas. Um exemplo ilustrativo para GitHub Actions é:

steps:
  - uses: actions/checkout@v4

  - uses: actions/setup-node@v4
    with:
      node-version-file: ".nvmrc"
      cache: "npm"

  - run: npm ci
  - run: npm run typecheck
  - run: npm test
  - run: npm run build

O YAML é ilustrativo. Use as versões de actions e os scripts que o repositório realmente mantém. A documentação atual do setup-node sobre cache e lockfiles mostra a relação entre cache, lockfile e npm ci; ela não garante que um cache esconda uma instalação inválida.

Para GitLab CI, a forma equivalente continua sendo explícita:

install:
  script:
    - npm ci

test:
  script:
    - npm run typecheck
    - npm test

O nome dos jobs muda, mas o princípio permanece. Não misture a etapa que modifica dependências com a etapa que verifica um commit. Se um job de atualização automática precisa executar npm install, faça isso em uma tarefa separada, produza o diff e peça revisão antes de aceitar o lockfile.

Por que npm ci ainda pode falhar?

Uma falha de npm ci não significa automaticamente que o comando está errado. Comece pela mensagem, depois investigue a fronteira que a mensagem aponta.

Manifesto e lockfile fora de sincronia

É o caso principal. Compare dependências, overrides, workspaces e versões declaradas. A documentação do npm também alerta que flags como --legacy-peer-deps e --install-links usadas ao criar o lockfile precisam ser reproduzidas no npm ci, ou a resolução pode falhar. Coloque essas opções em configuração de projeto quando fizer sentido, em vez de depender de uma memória local.

Workspace ou dependência local

Workspaces e dependências file: aumentam a superfície do lockfile. Um issue do npm CLI sobre dependências baseadas em arquivo, consultado em 26 de outubro de 2026, registra uma falha específica entre versões do npm em que npm ci rejeitava uma árvore criada depois de npm install. Use esse relato como pista para conferir versões, formato da dependência e reprodução mínima. Não o transforme em regra para todo projeto.

Dependência nativa ou opcional

Pacotes que variam por sistema operacional, arquitetura ou ferramenta disponível podem exigir uma investigação diferente. O issue do npm CLI sobre pacotes relacionados à arquitetura, consultado em 26 de outubro de 2026, mostra por que uma instalação que funciona em uma máquina não prova que o lockfile e os binários serão aceitos em outro runner.

Registre o sistema do runner, a versão de Node, a versão de npm, a configuração do projeto e a mensagem completa. Depois reduza o problema a uma fixture. Trocar para npm install sem guardar essa evidência apenas desloca o erro.

Scripts de instalação

Uma instalação limpa não é uma sandbox. O npm pode executar scripts de ciclo de vida necessários para compilar uma dependência nativa ou preparar o projeto. A discussão pública sobre scripts de instalação e fontes não registry, consultada em 26 de outubro de 2026, mostra a preocupação operacional, mas não substitui a documentação da versão de npm que sua equipe usa.

Se o projeto consegue funcionar sem scripts, npm ci --ignore-scripts pode ser uma opção de endurecimento. Se não consegue, documente quais scripts são necessários e execute o job sem segredos que não participam da instalação. Não use --ignore-scripts como uma promessa de segurança que não foi testada pelo próprio projeto.

Como separar desenvolvimento, CI e deploy?

As três situações têm objetivos diferentes. O mesmo comando pode aparecer em mais de uma delas, mas a razão precisa continuar clara:

Situação Comando inicial O que pode mudar Prova esperada
Adicionar ou atualizar dependência npm install Manifesto e lockfile Diff revisado e testes locais
Verificar um commit no CI npm ci Nada no manifesto ou lockfile Typecheck, testes e build
Instalar apenas runtime no deploy npm ci --omit=dev Nada no manifesto ou lockfile Smoke test do artefato implantado

O terceiro caso depende do modo como o aplicativo é empacotado. Um projeto que compila no CI precisa de devDependencies durante o build. Outro pode publicar somente o artefato compilado e instalar dependências de produção no ambiente final. A opção --omit=dev não deve ser colada no job de teste só porque parece mais enxuta.

O guia sobre quando usar teste unitário ou de integração em Node.js ajuda a escolher as provas depois da instalação. npm ci apenas deixa o conjunto de pacotes mais previsível. Ele não prova que o código compila, que os testes cobrem a mudança ou que o deploy consegue iniciar.

Checklist antes de trocar o comando

Antes de substituir npm ci por npm install, responda:

  • O package.json mudou sem uma atualização correspondente do lockfile?
  • A branch com a dependência inclui os dois arquivos no mesmo diff?
  • O CI usa a versão de Node e npm esperada pelo projeto?
  • Os flags da instalação local estão registrados e são repetidos no CI?
  • O projeto usa workspaces, dependências file: ou pacotes nativos?
  • O cache está baseado no lockfile e pode ser descartado para reproduzir o erro?
  • Os scripts de instalação precisam de rede, credenciais ou binários extras?
  • Depois de instalar, o job executa typecheck, testes e build?

Se a resposta aponta para um lockfile desatualizado, faça a mudança localmente, revise o diff e commite o resultado. Se aponta para o runner, reproduza em uma fixture com a mesma versão de Node e npm. Só troque o comando quando o objetivo do job também tiver mudado.

Perguntas frequentes

Posso usar npm install no CI?

Pode, mas isso dá ao job autorização para resolver e atualizar dependências conforme o manifesto e o estado local. Para uma verificação de commit, essa mutação é um risco de reprodutibilidade. Use npm ci quando o lockfile faz parte do contrato e reserve npm install para um job que cria uma atualização deliberada e revisável.

npm ci instala exatamente o que está no lockfile?

Ele instala a árvore representada pelo lockfile quando o manifesto e a configuração são compatíveis. O comando falha diante de divergências, remove node_modules existente e não grava os arquivos de dependência. Isso não elimina diferenças do sistema, scripts, versão do runtime ou dependências nativas. Verifique o ambiente junto com o lockfile.

Devo apagar o package-lock.json quando npm ci falha?

Não como primeiro passo. Apagar o lockfile remove a evidência que o CI está protegendo e permite uma nova resolução sem revisão. Compare os arquivos, confirme a versão do npm e reproduza o caso. Regere o lockfile apenas quando essa for uma mudança intencional, então revise e commite o resultado.

Conclusão

npm install é a ferramenta para mudar a árvore de dependências. npm ci é a verificação que restaura uma árvore já declarada e falha quando o commit não a descreve com precisão.

Use o primeiro durante uma alteração consciente. Use o segundo antes de typecheck, testes e build. Quando o CI falhar, trate a mensagem como evidência sobre o manifesto, o lockfile, os flags ou o runner. Fazer o pipeline verde instalando outra coisa resolve o sintoma e enfraquece a prova que o pipeline deveria entregar.

Como este artigo foi produzido

Samuel Fajreldines é o autor responsável. A pesquisa comparou a documentação atual do npm sobre install e ci, a orientação do setup-node para lockfiles, resultados de busca em português, inglês e espanhol e discussões públicas usadas apenas para vocabulário e falhas de operação.

A fixture local usou Node v25.5.0 e npm 11.8.0 em 26 de outubro de 2026. Ela demonstrou a falha de npm ci quando o manifesto e o lockfile discordam e a correção com npm install. O teste não é benchmark, não cobre todos os workspaces e não é uma auditoria de segurança.

Usei assistência de IA para descoberta de fontes, comparação, organização, redação, geração da imagem, localização e revisão de consistência. A assistência não substituiu a execução da fixture nem acrescentou experiência de projeto que não foi realizada.

Fontes consultadas