Primeiros Passos com npm Workspaces
Configuração, comandos e limites do npm workspaces para gerenciar um monorepo, vincular pacotes internos e saber quando adicionar Turborepo ou Nx.
Os npm workspaces, integrados ao npm desde a versão 7, permitem gerenciar vários pacotes em um único repositório — um monorepo — a partir de uma raiz única: um único npm install eleva as dependências compartilhadas para um único node_modules raiz e cria symlinks dos seus próprios pacotes ali, de modo que as importações entre pacotes são resolvidas sem npm link e sem republicações. Se você tem uma aplicação com uma biblioteca compartilhada, ou uma biblioteca de componentes com seu site de documentação, e está cansado de usar npm link, copiar e colar código, ou gerenciar repositórios separados, este é o recurso nativo que elimina esse atrito — sem necessidade de ferramentas de terceiros. Este guia aborda a configuração mínima, os flags exatos dos comandos, as limitações reais e quando adicionar um orquestrador de build por cima.
Principais Conclusões
- Os npm workspaces estão disponíveis a partir do npm 7+; a versão atual é npm 11.18.0, e você pode confirmar a sua versão com
npm -v. - A configuração mínima consiste em dois arquivos: um
package.jsonraiz com"private": truee"workspaces": ["packages/*"], mais umpackage.jsonpor pacote — então um úniconpm installna raiz conecta tudo. - Para depender de um pacote irmão, adicione-o pelo nome com o range
"*"; o npm cria um symlink na instalação, de modo que as edições no código-fonte ficam visíveis em todos os consumidores imediatamente, sem necessidade de rebuild ou republicação. - Os npm workspaces resolvem e vinculam dependências, mas não executam tarefas em ordem de dependência, não fazem cache de saídas de build, nem calculam um grafo de pacotes “afetados”.
- Utilize Turborepo ou Nx em conjunto com os npm workspaces, não em substituição a eles — o npm resolve e vincula os pacotes; essas ferramentas adicionam orquestração de tarefas e cache.
Como funcionam os npm workspaces?
Os npm workspaces transformam um único repositório em um monorepo ao elevar as dependências compartilhadas para um único node_modules raiz e criar symlinks dos seus próprios pacotes ao lado delas. Quando você executa npm install na raiz, o npm varre todos os workspaces, instala as dependências de terceiros uma única vez no nível superior e vincula cada pacote local ao node_modules pelo seu campo name. Se dois dos seus pacotes dependem um do outro, a referência é resolvida por meio desse symlink — o npm CLI automatiza a vinculação como parte do npm install e elimina a necessidade de executar npm link manualmente.
O mesmo campo workspaces e o modelo de symlinks também são utilizados pelo Yarn, pnpm e Bun, portanto o modelo mental se transfere entre gerenciadores de pacotes. O recurso foi introduzido no npm 7; qualquer versão mais recente funciona.
Discover how at OpenReplay.com.
Qual é a configuração mínima dos npm workspaces?
A configuração mínima consiste em dois arquivos: um package.json raiz que declara onde os pacotes estão localizados, mais um package.json por pacote. Crie esta estrutura:
my-monorepo/
├── package.json # raiz — private, lista os workspaces
└── packages/
├── utils/
│ └── package.json # @myorg/utils
└── app/
└── package.json # @myorg/app
O package.json raiz precisa de dois campos:
{
"name": "my-monorepo",
"private": true,
"workspaces": ["packages/*"]
}
"private": true impede que você publique a raiz acidentalmente, e o glob packages/* instrui o npm a tratar cada diretório dentro de packages/ como um workspace. Dê a cada pacote um nome com escopo como @myorg/utils para evitar colisões no registry:
{
"name": "@myorg/utils",
"version": "1.0.0",
"main": "dist/index.js"
}
Execute npm install uma única vez na raiz. Há um único lockfile na raiz e nenhum node_modules dentro dos pacotes individuais — tudo é elevado para o nível superior.
Adicionar uma dependência entre pacotes
Para depender de um pacote irmão, adicione-o pelo nome com o range "*"; o npm cria um symlink na instalação, de modo que as edições no código-fonte ficam visíveis em todos os consumidores imediatamente. Em @myorg/app:
{
"name": "@myorg/app",
"dependencies": {
"@myorg/utils": "*"
}
}
Execute npm install na raiz novamente. O npm cria um symlink de node_modules/@myorg/utils para packages/utils, e você o importa como qualquer módulo publicado:
import { formatDate } from "@myorg/utils";
Por ser um symlink, alterar o código-fonte em packages/utils é refletido em app sem necessidade de rebuild ou republicação — esta é a vantagem em relação ao npm link. Uma ressalva entre ferramentas: o npm não suporta o protocolo de versão workspace: utilizado pelo pnpm e pelo Yarn Berry. Passar um especificador workspace: faz o npm falhar com EUNSUPPORTEDPROTOCOL, portanto, com o npm, você referencia pacotes internos pelo nome e range ("*"), não com workspace:*.
Os comandos do dia a dia
Os flags costumam causar confusão porque singular e plural têm significados diferentes. Adicione uma dependência a um pacote com -w, a todos os pacotes com --workspaces; execute um script em um workspace com -w, e em todos eles com --workspaces --if-present, que ignora os pacotes que não definem aquele script.
# Instalar uma dependência em UM workspace
npm install lodash -w @myorg/app
# Instalar uma dependência de desenvolvimento em um workspace
npm install -D vitest -w @myorg/utils
# Instalar uma dependência em TODOS os workspaces
npm install eslint --workspaces
# Executar um script em UM workspace
npm run build -w @myorg/utils
# Executar um script em TODOS os workspaces, ignorando os que não o definem
npm run test --workspaces --if-present
-w é a abreviação de --workspace, e --workspaces (ou -ws) tem como alvo todos eles. Configure os scripts raiz uma única vez para que npm run build seja distribuído:
{
"scripts": {
"build": "npm run build --workspaces --if-present",
"test": "npm run test --workspaces --if-present"
}
}
Para verificar se o grafo está vinculado, execute npm ls -ws ou consulte-o com npm query .workspace.
As limitações: o que os npm workspaces não fazem
Os npm workspaces resolvem e vinculam dependências, mas não executam tarefas em ordem de dependência, não fazem cache de saídas de build, nem calculam um grafo de pacotes “afetados”. Se sua aplicação importa uma biblioteca, você deve compilar a biblioteca primeiro — executar um script em todos os workspaces resultará em erro quando eles dependem uns dos outros, pois o npm não executa em ordem topológica, uma melhoria que ainda está pendente. Ordene explicitamente, ou utilize npm-run-all:
{
"scripts": {
"build:utils": "npm run build -w @myorg/utils",
"build:app": "npm run build -w @myorg/app",
"build": "npm run build:utils && npm run build:app"
}
}
Mais dois pontos de atenção:
-
node_modulesaninhados. Quando dois pacotes requerem versões incompatíveis da mesma dependência, o npm interrompe a elevação e instala uma cópia aninhada dentro de um dos pacotes. Fixe uma única versão compartilhada com o campooverridesna raiz para manter a árvore plana:{ "overrides": { "lodash": "^4.17.21" } } -
Os padrões de scripts de instalação estão se tornando mais restritivos. O npm v12, com lançamento previsto para julho de 2026, altera
allowScriptspara desativado por padrão, de modo que onpm installnão executará mais os scriptspreinstall,installoupostinstalldas dependências, a menos que sejam explicitamente permitidos. Se seus workspaces dependem de uma etapa de build viapostinstallouprepare, planeje aprová-la — essas mudanças aparecem como avisos no npm 11.16.0 ou mais recente para que você possa se preparar com antecedência.
Observe que “sem integração nativa com React/Vue/Vite” é uma declaração de escopo, não um defeito: os workspaces são agnósticos em relação a frameworks por design. Criar scaffolding de aplicações não é sua função.
Quando recorrer ao Turborepo ou ao Nx
Utilize o Turborepo ou o Nx em conjunto com os npm workspaces, não em substituição a eles: o npm resolve e vincula seus pacotes, enquanto essas ferramentas adicionam orquestração de tarefas, cache e builds baseados em grafo de pacotes afetados para repositórios maiores. São camadas complementares.
| Preocupação | npm workspaces | Turborepo / Nx |
|---|---|---|
| Instalar e vincular pacotes | ✅ | Delega ao npm |
| Ordem de dependência de tarefas | ❌ scripts manuais | ✅ topológica |
| Cache de build/test | ❌ | ✅ local + remoto |
| Builds “afetados” | ❌ | ✅ grafo baseado em mudanças |
Adicione uma dessas ferramentas quando os scripts ordenados se tornarem difíceis de gerenciar, quando o CI recompilar tudo a cada mudança, ou quando você quiser executar tarefas apenas para os pacotes afetados por um commit. Observe que o Lerna moderno agora é baseado no Nx — o antigo conselho de “npm + Lerna” foi incorporado a essa mesma abordagem em camadas.
Os npm workspaces cobrem aproximadamente os primeiros 80% das necessidades de monorepos pequenos sem nenhuma ferramenta adicional. Configure os dois arquivos, defina seus flags, ordene seus builds e adicione um orquestrador somente quando o pipeline — e não a resolução de dependências — se tornar o gargalo. Execute em uma versão Active LTS do Node (o Node 20 chegou ao fim de vida em 30/04/2026) e confirme que npm -v reporta 7 ou mais recente antes de começar.
Perguntas Frequentes
Os npm workspaces ainda precisam de um lockfile por pacote, ou apenas um na raiz?
Os npm workspaces produzem um único package-lock.json na raiz do repositório, não um por pacote. Um npm install na raiz resolve as dependências de todos os workspaces em conjunto e as registra nesse único lockfile, enquanto os pacotes individuais não têm seu próprio diretório node_modules, pois as dependências são elevadas para a raiz. Esse modelo de lockfile único é o que mantém as versões consistentes em todos os pacotes e é por isso que você sempre executa o install a partir da raiz.
Por que 'npm run build --workspaces' falha quando meus pacotes dependem uns dos outros?
Falha porque o npm não executa scripts de workspace em ordem topológica (de dependência); ele os executa na ordem em que os workspaces estão listados, de modo que um consumidor pode ser compilado antes que a biblioteca que ele importa exista, produzindo erros de 'cannot find module' ou falhas de resolução. Isso ainda é uma melhoria pendente no npm (issue 4139). Corrija definindo scripts ordenados explicitamente que compilem a biblioteca primeiro, ou utilizando uma ferramenta como npm-run-all, Turborepo ou Nx.
Posso usar o protocolo 'workspace:*' com o npm como faço no pnpm ou no Yarn?
Não. O npm não suporta o protocolo de versão workspace: utilizado pelo pnpm e pelo Yarn Berry, e passar um especificador workspace: faz o npm falhar com EUNSUPPORTEDPROTOCOL (documentado na issue 8845 do npm/cli). Com o npm, referencie pacotes internos pelo nome e um range normal, como '@myorg/utils': '*'; o npm cria symlinks deles na instalação. Se você migrar um repositório pnpm ou Yarn para o npm, reescreva todos os especificadores workspace: para um range simples.
Ainda preciso do 'npm link' ao usar workspaces?
Não. Os npm workspaces automatizam a vinculação como parte do npm install, criando symlinks de cada pacote local no node_modules raiz pelo seu campo name, o que elimina a necessidade de executar npm link manualmente. Uma vez que um pacote lista um irmão como dependência com o range '*', um único npm install na raiz cria o symlink, e as edições no pacote de origem ficam visíveis em todos os consumidores imediatamente, sem necessidade de rebuild ou republicação.
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