O que é npm?
O npm é o gerenciador de pacotes padrão para JavaScript e o maior registro de software do mundo. Ele vem junto com o Node.js, instala as dependências que seu projeto declara, resolve suas versões e oferece um executor de tarefas consistente por meio de scripts.
Quase todo projeto JavaScript depende do npm, mesmo que utilize um cliente diferente por baixo dos panos. Entender o que ele realmente faz — como as versões são resolvidas, para que serve o lockfile e por que o CI utiliza um comando diferente — elimina toda uma categoria de erros confusos.
package.json
O manifesto descreve o seu projeto. Ele contém metadados, dependências e scripts.
{
"name": "my-app",
"version": "1.0.0",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"test": "vitest run",
"lint": "eslint ."
},
"dependencies": {
"react": "^19.0.0",
"react-dom": "^19.0.0"
},
"devDependencies": {
"vite": "^6.0.0",
"vitest": "^3.0.0"
}
}
dependencies são necessárias em tempo de execução; devDependencies são ferramentas usadas para desenvolver e buildar. A flag private evita a publicação acidental, e type: "module" ativa o uso de ES modules.
Intervalos de versão
O npm utiliza versionamento semântico: major.minor.patch. Um intervalo em package.json descreve quais atualizações você aceita.
| Intervalo | Significado | Permite |
|---|---|---|
1.2.3 |
exata | nada |
~1.2.3 |
atualizações de patch | 1.2.4, 1.2.5 |
^1.2.3 |
minor e patch | 1.3.0, 1.4.2 |
* |
qualquer uma | qualquer versão |
O caret (^) é o padrão e a escolha mais sensata para a maioria das dependências. Versões exatas bloqueiam correções de bugs e patches de segurança, enquanto o lockfile já garante a reprodutibilidade.
O lockfile
O package-lock.json registra a versão exata e o hash de integridade de cada pacote na árvore, incluindo as dependências transitivas.
- Faça o commit dele no controle de versão.
- Nunca o edite manualmente.
- Regenere-o deliberadamente quando pretender atualizar.
- Deixe que ele seja a única fonte de verdade para as versões instaladas.
Sem um lockfile, duas instalações do mesmo package.json podem gerar árvores diferentes, e um bug que aparece apenas em produção torna-se quase impossível de reproduzir.
Instalando dependências
Os dois principais comandos de instalação têm propósitos diferentes.
# development: resolve ranges, may update the lockfile
npm install
# CI and clean environments: exact install from the lockfile
npm ci
# add a runtime dependency
npm install zod
# add a development tool
npm install -D vitest
npm ci deleta a pasta node_modules, instala estritamente a partir do lockfile e falha se package.json e o lockfile estiverem divergentes. Isso o torna mais rápido e seguro em CI. Use npm install localmente quando estiver alterando dependências.
Scripts
Scripts são comandos nomeados executados através do npm run. É assim que um projeto expõe uma interface consistente para todos, incluindo a CI.
npm run dev
npm run build
npm test # shorthand for npm run test
Scripts podem chamar binários locais diretamente, portanto o "dev": "vite" funciona sem a necessidade de uma instalação global. Eles também são compostos: um script ci pode executar lint, test e build em sequência. Manter esses comandos no package.json garante que ninguém precise lembrar a invocação exata.
npx e workspaces
O npx executa o binário de um pacote sem a necessidade de instalação global, o que é ideal para ferramentas de uso pontual.
npx create-vite@latest my-app
npx eslint .
Workspaces permitem que um único repositório contenha vários pacotes que compartilham um único node_modules e lockfile.
{
"workspaces": ["packages/*", "apps/*"]
}
O npm vincula os pacotes entre si, permitindo que um workspace dependa de um pacote irmão sem a necessidade de publicá-lo. Para monorepos maiores, ferramentas como Turborepo adicionam cache e orquestração de tarefas.
Segurança e manutenção
O npm inclui um comando de audit que verifica a sua árvore de dependências em busca de vulnerabilidades conhecidas.
npm audit
npm audit fix
npm outdated
Faça o audit regularmente e analise os resultados em vez de executar cegamente o fix, que pode introduzir breaking changes. O npm outdated mostra quais dependências possuem versões mais recentes disponíveis, o que ajuda você a planejar as atualizações em vez de deixá-las se acumularem.
Melhores práticas
- Faça o commit de
package-lock.jsone nunca o edite manualmente. - Use
npm cino CI enpm installapenas ao alterar dependências. - Mantenha as dependencies e devDependencies separadas.
- Prefira caret ranges e deixe que o lockfile fixe as versões exatas.
- Defina scripts para cada tarefa comum.
- Execute
npm auditenpm outdatedperiodicamente. - Use workspaces para monorepos em vez de repositórios separados.
Erros comuns
- Deletar o lockfile para “corrigir” problemas de instalação.
- Executar
npm installem CI e obter builds não reprodutíveis. - Colocar ferramentas de build em
dependenciese inflar as instalações de runtime. - Ignorar avisos de audit até que se tornem urgentes.
- Instalar pacotes globalmente quando
npxou uma devDependency resolveriam. - Editar
node_modulese esperar que a alteração persista.
Próximos passos
O npm é a base da toolchain de JavaScript. Compare-o com o pnpm para ganhar velocidade e eficiência de disco, entenda o runtime do Node.js com o qual ele vem e adicione o Turborepo quando seu repositório crescer para um monorepo. Depois, organize os scripts do projeto para que toda a equipe compartilhe um único conjunto de comandos.