Managing Shared Local Libraries with npm Workspaces
Stop the publish-update cycle. Learn how to use npm workspaces to manage local shared libraries and applications in a single monorepo with automatic symlinking and dependency hoisting.
26 Apr 2026, 17:03 UTC

The Local Dependency Loop
When building a project that requires a shared utility library, the typical workflow is frustrating: make a change in the library, publish it to a registry (or use npm link), and then update the version in the main application. This cycle creates friction and often leads to "version drift," where the library in production differs from the one used during local development.
The solution is npm workspaces. Introduced in npm v7, workspaces allow you to manage multiple packages within a single root directory. Instead of treating your library as a remote dependency, npm treats it as a local symlink. Changes in your shared library are reflected in your application instantly, without requiring a publish cycle.
Defining the Workspace Structure
To implement workspaces, you must define a root package.json that acts as the orchestrator. You do not necessarily need to install dependencies at the root, but the root file must tell npm where your sub-packages live using the workspaces field.
The most common pattern is to group all sub-packages into a packages/ directory. This keeps the root clean and allows you to add new libraries or apps without updating the root configuration every time.
Hoisting and the Node Modules Tree
One of the primary technical benefits of workspaces is hoisting. When you run npm install at the root, npm analyzes the dependencies of every workspace. If multiple packages use the same version of a dependency (e.g., lodash), npm "hoists" that dependency to the root node_modules folder.
This reduces disk space and ensures that shared dependencies are singleton instances, which is critical for libraries that rely on internal state or specific instance checks.
Worked Example: Shared UI Utilities
Consider a scenario where you have a web-app and a ui-shared library. Here is how to configure and verify the link.
1. Root Configuration
In your root directory, create a package.json:
{
"name": "my-monorepo",
"private": true,
"workspaces": [
"packages/*"
]
}2. Package Setup
Create the following directory structure:
packages/ui-shared/package.json(name:"@my-project/ui-shared")packages/web-app/package.json(name:"web-app")
In packages/web-app/package.json, add the shared library as a dependency:
{
"dependencies": {
"@my-project/ui-shared": "*"
}
}3. Installation and Execution
Run the following command from the root directory with standard user permissions:
npm installVerification: Check the root node_modules. You should see a symlink for @my-project/ui-shared pointing directly to your packages/ui-shared folder. You can now run scripts for specific packages from the root using the -w flag:
npm test -w @my-project/ui-sharedRollback
To revert to isolated packages, remove the workspaces field from the root package.json and delete the root node_modules and package-lock.json before running npm install inside each individual package directory.
Trade-offs and Limitations
While workspaces simplify development, they introduce the risk of phantom dependencies. Because of hoisting, a package might be able to import a module that it hasn't explicitly listed in its own package.json, simply because another workspace required it and it was hoisted to the root.
This can lead to runtime crashes in production if the package is eventually deployed independently without that hoisted dependency. To mitigate this, always ensure every package explicitly declares its own dependencies, regardless of whether they are hoisted.
Actionable Summary
To move to an npm workspace model: define your workspaces array in the root, move your local libraries into that path, and use npm install at the root to create the symlinks. Use npm install -w [package-name] [dependency] to add specific libraries to sub-packages without leaving the root directory.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.