Primeros pasos con npm Workspaces
Configuración, comandos y límites de npm workspaces para gestionar un monorepo, vincular paquetes internos y saber cuándo añadir Turborepo o Nx.
npm workspaces, integrado en npm desde la versión 7, permite gestionar varios paquetes en un único repositorio — un monorepo — desde una raíz común: un solo npm install eleva las dependencias compartidas a un único node_modules raíz y crea symlinks de tus propios paquetes allí, de modo que las importaciones entre paquetes se resuelven sin necesidad de npm link ni de volver a publicar. Si tienes una aplicación junto con una librería compartida, o una librería de componentes junto con su sitio de documentación, y estás harto de npm link, de copiar y pegar código o de gestionar repositorios separados, esta es la funcionalidad nativa que elimina esa fricción — sin necesidad de herramientas de terceros. Esta guía cubre la configuración mínima, los flags exactos de los comandos, las limitaciones reales y cuándo conviene añadir un orquestador de builds encima.
Puntos clave
- npm workspaces viene incluido en npm 7+; la versión actual es npm 11.18.0, y puedes confirmar tu versión con
npm -v. - La configuración mínima consta de dos archivos: un
package.jsonraíz con"private": truey"workspaces": ["packages/*"], más unpackage.jsonpor paquete — luego un úniconpm installen la raíz lo conecta todo. - Para depender de un paquete hermano, agrégalo por nombre con un rango
"*"; npm crea el symlink al instalar, por lo que los cambios en el código fuente son visibles en cada consumidor de inmediato, sin necesidad de reconstruir ni volver a publicar. - npm workspaces resuelve y enlaza dependencias, pero no ejecuta tareas en orden de dependencia, no cachea las salidas de build ni calcula un grafo de paquetes “afectados”.
- Usa Turborepo o Nx encima de npm workspaces, no en su lugar — npm resuelve y enlaza los paquetes; esas herramientas añaden orquestación de tareas y caché.
¿Cómo funcionan npm workspaces?
npm workspaces convierte un único repositorio en un monorepo elevando las dependencias compartidas a un único node_modules raíz y creando symlinks de tus propios paquetes junto a ellas. Cuando ejecutas npm install en la raíz, npm analiza cada workspace, instala las dependencias de terceros una sola vez en el nivel superior y enlaza cada paquete local en node_modules mediante su campo name. Si dos de tus paquetes dependen entre sí, la referencia se resuelve a través de ese symlink — el CLI de npm automatiza el enlazado como parte de npm install y elimina la necesidad de ejecutar npm link manualmente.
El mismo campo workspaces y el modelo de symlinks también son utilizados por Yarn, pnpm y Bun, por lo que el modelo mental se transfiere entre gestores de paquetes. La funcionalidad llegó en npm 7; cualquier versión posterior funciona.
Discover how at OpenReplay.com.
¿Cuál es la configuración mínima de npm workspaces?
La configuración mínima consta de dos archivos: un package.json raíz que declara dónde viven los paquetes, más un package.json por paquete. Crea esta estructura:
my-monorepo/
├── package.json # raíz — private, lista los workspaces
└── packages/
├── utils/
│ └── package.json # @myorg/utils
└── app/
└── package.json # @myorg/app
El package.json raíz necesita dos campos:
{
"name": "my-monorepo",
"private": true,
"workspaces": ["packages/*"]
}
"private": true evita que publiques accidentalmente la raíz, y el glob packages/* le indica a npm que trate cada directorio bajo packages/ como un workspace. Asigna a cada paquete un nombre con scope como @myorg/utils para evitar colisiones en el registro:
{
"name": "@myorg/utils",
"version": "1.0.0",
"main": "dist/index.js"
}
Ejecuta npm install una sola vez en la raíz. Existe un único lockfile en la raíz y no hay node_modules dentro de los paquetes individuales — todo se eleva hacia arriba.
Añadir una dependencia entre paquetes
Para depender de un paquete hermano, agrégalo por nombre con un rango "*"; npm crea el symlink al instalar, por lo que los cambios en el código fuente son visibles en cada consumidor de inmediato. En @myorg/app:
{
"name": "@myorg/app",
"dependencies": {
"@myorg/utils": "*"
}
}
Ejecuta npm install en la raíz nuevamente. npm crea un symlink desde node_modules/@myorg/utils hacia packages/utils, y lo importas como cualquier módulo publicado:
import { formatDate } from "@myorg/utils";
Al ser un symlink, los cambios en el código fuente de packages/utils se reflejan en app sin necesidad de reconstruir ni volver a publicar — esta es la ventaja frente a npm link. Una advertencia entre herramientas: npm no soporta el protocolo de versión workspace: que utilizan pnpm y Yarn Berry. Pasar un especificador workspace: hace que npm falle con EUNSUPPORTEDPROTOCOL, por lo que con npm debes referenciar los paquetes internos por nombre y rango ("*"), no con workspace:*.
Los comandos del día a día
Los flags suelen generar confusión porque el singular y el plural tienen significados distintos. Añade una dependencia a un paquete con -w, a todos los paquetes con --workspaces; ejecuta un script en un workspace con -w, y en todos ellos con --workspaces --if-present, que omite los paquetes que no definen ese script.
# Instalar una dependencia en UN workspace
npm install lodash -w @myorg/app
# Instalar una dependencia de desarrollo en un workspace
npm install -D vitest -w @myorg/utils
# Instalar una dependencia en TODOS los workspaces
npm install eslint --workspaces
# Ejecutar un script en UN workspace
npm run build -w @myorg/utils
# Ejecutar un script en TODOS los workspaces, omitiendo los que no lo definen
npm run test --workspaces --if-present
-w es la forma abreviada de --workspace, y --workspaces (o -ws) apunta a todos ellos. Configura los scripts raíz una sola vez para que npm run build se propague:
{
"scripts": {
"build": "npm run build --workspaces --if-present",
"test": "npm run test --workspaces --if-present"
}
}
Para verificar que el grafo está enlazado, ejecuta npm ls -ws o consúltalo con npm query .workspace.
Las limitaciones: qué no hará npm workspaces
npm workspaces resuelve y enlaza dependencias, pero no ejecuta tareas en orden de dependencia, no cachea las salidas de build ni calcula un grafo de paquetes “afectados”. Si tu aplicación importa una librería, debes compilar la librería primero — ejecutar un script en todos los workspaces producirá errores cuando dependen entre sí, porque npm no ejecuta en orden topológico, una mejora que sigue pendiente. Ordénalo explícitamente, o usa 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"
}
}
Dos advertencias adicionales:
-
node_modulesanidados. Cuando dos paquetes requieren versiones incompatibles de la misma dependencia, npm deja de elevarla e instala una copia anidada dentro de uno de los paquetes. Fija una única versión compartida con el campooverridesen la raíz para mantener el árbol plano:{ "overrides": { "lodash": "^4.17.21" } } -
Los valores predeterminados para scripts de instalación se están endureciendo. npm v12, con lanzamiento estimado para julio de 2026, cambia
allowScriptspara que esté desactivado por defecto, por lo quenpm installya no ejecutará los scriptspreinstall,installopostinstallde las dependencias a menos que se permitan explícitamente. Si tus workspaces dependen de un paso de build enpostinstalloprepare, planifica aprobarlo — estos cambios aparecen como advertencias en npm 11.16.0 o posterior para que puedas prepararte con anticipación.
Cabe señalar que “sin integración nativa con React/Vue/Vite” es una declaración de alcance, no un defecto: los workspaces son agnósticos al framework por diseño. El scaffolding de aplicaciones no es su función.
Cuándo recurrir a Turborepo o Nx
Usa Turborepo o Nx encima de npm workspaces, no en su lugar: npm resuelve y enlaza tus paquetes, mientras que esas herramientas añaden orquestación de tareas, caché y builds basados en el grafo de cambios para repositorios más grandes. Son capas complementarias.
| Aspecto | npm workspaces | Turborepo / Nx |
|---|---|---|
| Instalar y enlazar paquetes | ✅ | Delega en npm |
| Orden de dependencia en tareas | ❌ scripts manuales | ✅ topológico |
| Caché de build/test | ❌ | ✅ local + remoto |
| Builds “afectados” | ❌ | ✅ grafo basado en cambios |
Añade uno cuando los scripts ordenados se vuelven difíciles de mantener, cuando CI reconstruye todo en cada cambio, o cuando quieres ejecutar tareas solo para los paquetes que un commit modificó. Ten en cuenta que el Lerna moderno ahora está respaldado por Nx — el consejo clásico de “npm + Lerna” ha quedado absorbido en este mismo esquema de capas.
npm workspaces cubre aproximadamente el 80% inicial de las necesidades de monorepos pequeños sin herramientas adicionales. Configura los dos archivos, define tus flags, ordena tus builds y añade un orquestador solo cuando el pipeline — no la resolución de dependencias — se convierta en el cuello de botella. Ejecuta en una versión Active LTS de Node (Node 20 llegó a su fin de vida el 30 de abril de 2026) y confirma que npm -v reporta 7 o superior antes de comenzar.
Preguntas frecuentes
¿npm workspaces sigue necesitando un lockfile por paquete, o uno en la raíz?
npm workspaces genera un único package-lock.json en la raíz del repositorio, no uno por paquete. Un npm install en la raíz resuelve las dependencias de todos los workspaces de forma conjunta y las registra en ese único lockfile, mientras que los paquetes individuales no tienen su propio directorio node_modules porque las dependencias se elevan a la raíz. Este modelo de lockfile único es lo que mantiene las versiones consistentes en todos los paquetes y es la razón por la que siempre debes ejecutar install desde la raíz.
¿Por qué falla 'npm run build --workspaces' cuando mis paquetes dependen entre sí?
Falla porque npm no ejecuta los scripts de workspace en orden topológico (de dependencia); los ejecuta en el orden en que están listados los workspaces, por lo que un consumidor puede compilarse antes de que exista la librería que importa, produciendo errores de tipo 'cannot find module' o fallos de resolución. Esto sigue siendo una mejora pendiente en npm (issue 4139). Corrígelo definiendo scripts ordenados explícitamente que compilen la librería primero, o usando una herramienta como npm-run-all, Turborepo o Nx.
¿Puedo usar el protocolo 'workspace:*' con npm como lo hago en pnpm o Yarn?
No. npm no soporta el protocolo de versión workspace: utilizado por pnpm y Yarn Berry, y pasar un especificador workspace: hace que npm falle con EUNSUPPORTEDPROTOCOL (documentado en el issue 8845 de npm/cli). Con npm, referencia los paquetes internos por su nombre y un rango normal como '@myorg/utils': '*'; npm los enlaza mediante symlinks al instalar. Si migras un repositorio de pnpm o Yarn a npm, reescribe cada especificador workspace: por un rango normal.
¿Sigo necesitando 'npm link' al usar workspaces?
No. npm workspaces automatiza el enlazado como parte de npm install, creando symlinks de cada paquete local en el node_modules raíz mediante su campo name, lo que elimina la necesidad de ejecutar npm link manualmente. Una vez que un paquete lista a un hermano como dependencia con un rango '*', un único npm install en la raíz configura el symlink, y los cambios en el paquete fuente son visibles en cada consumidor de inmediato, sin necesidad de reconstruir ni volver a publicar.
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