Managing Local Package Dependencies with Yarn Workspaces
Learn how to implement Yarn Workspaces to manage multiple packages in a single repository, optimize dependency hoisting, and link local packages without manual publishing.
16 Oct 2025, 03:42 UTC

The Monorepo Dependency Problem
When developing multiple related packages—such as a shared UI library and several applications that consume it—managing versions and local updates becomes a bottleneck. Manually running npm link or publishing beta versions to a registry for every change is slow and error-prone. The goal is to treat local packages as if they were published modules while maintaining a single source of truth for dependencies.
Prerequisites
- Node.js installed (LTS recommended).
- Yarn installed (v1.x Classic or v2+ Berry).
- A project structure where packages are grouped in a specific directory (e.g.,
/packages).
Configuring the Workspace Root
Yarn Workspaces requires a root package.json to act as the orchestrator. This root file does not necessarily need to be a publishable package itself, but it must define where the sub-packages live.
Run the following in your project root to initialize the configuration:
# Create the root package.json if it doesn't exist
yarn init -y
Edit the root package.json to include the workspaces field. This field accepts an array of globs (directory patterns):
{
"name": "my-monorepo",
"private": true,
"workspaces": [
"packages/*"
]
}
Note: The "private": true flag is mandatory. Yarn will not allow workspaces in a project that can be published to a registry.
Linking Local Packages
To make one workspace depend on another, you list the local package's name (as defined in its own package.json) in the dependencies of the consuming package.
Example Configuration
Assume a structure with a shared utility library and a web app:
/packages/utils/package.json(name:@my-project/utils)/packages/web-app/package.json(name:@my-project/web-app)
In /packages/web-app/package.json, add the dependency:
{
"name": "@my-project/web-app",
"dependencies": {
"@my-project/utils": "1.0.0"
}
}
Run the installation from the root directory:
# Run from project root with standard user permissions
yarn install
Managing and Executing Workspace Commands
You do not need to change directories to run scripts inside a specific package. Use the workspace command from the root.
| Task | Command (Run from Root) | Expected Result |
|---|---|---|
| Add dependency to specific package | yarn workspace <name> add <pkg> |
Updated package.json in sub-folder |
| Run a script in a package | yarn workspace <name> run build |
Execution of the 'build' script in that package |
| Install all dependencies | yarn install |
Single yarn.lock created at root |
Verification and Diagnostics
To ensure the workspace is functioning correctly, perform these three checks:
- Lockfile Check: Verify that only one
yarn.lockexists at the root. Sub-packages should not have their own lockfiles. - Hoisting Check: Inspect
/node_modulesat the root. Dependencies shared by multiple workspaces (e.g.,lodash) should be located here rather than duplicated in every sub-package. - Symlink Check: Navigate to
/packages/web-app/node_modules/@my-project/. Theutilsfolder should be a symbolic link pointing back to/packages/utils.
Handling Hoisting Risks
Yarn uses hoisting to move dependencies to the root to save space. This can cause "phantom dependencies," where a package can import a module it didn't explicitly list because that module was hoisted from another workspace.
Diagnostic: If a package works locally but fails in CI/CD, check if it relies on a dependency that is missing from its own package.json but present in the root node_modules.
Recovery and State Reset
If symlinks become corrupted or hoisting causes version conflicts, reset the environment by removing all generated artifacts:
# Run from project root
rm -rf node_modules
rm -rf packages/*/node_modules
yarn install0 replies
A thoughtful contribution can make all the difference. Be the first to share one.