Difference between Isolated node_modules and Hoisted node_modules
Muhammad Athar
Muhammad Athar
1. Isolated node_modules
- Definition: Each package or sub-project in a monorepo has its own
node_modules
directory, containing all the dependencies it needs. - Structure:Example:/project /packages /package-a /node_modules react /package-b /node_modules react
- Each package manages its dependencies independently.
- Dependencies are installed locally within the
node_modules
of each package. - There is no sharing of dependencies between packages.
- Advantages:
- Isolation: Each package is self-contained, so changes in one package's dependencies do not affect others.
- Predictability: Dependency resolution is straightforward because each package has its own isolated environment.
- Fewer conflicts: Different versions of the same dependency can coexist in different packages.
- Disadvantages:
- Redundancy: Dependencies are duplicated across packages, leading to increased disk space usage.
- Slower installs: Installing dependencies for each package separately can take more time.
2. Hoisted node_modules
- Definition: Dependencies are "hoisted" to a common
node_modules
directory at the root of the project, shared across all packages in the monorepo. - Structure:Example:/project /node_modules react /packages /package-a /package-b
- Dependencies are installed at the root level of the monorepo (or a workspace).
- Shared dependencies are deduplicated and placed in the root
node_modules
. - Each package may still have its own
node_modules
for dependencies that cannot be hoisted (e.g., conflicting versions).
- Advantages:
- Deduplication: Shared dependencies are installed only once, saving disk space.
- Faster installs: Dependencies are resolved and installed at the root level, reducing redundancy.
- Consistency: Ensures that all packages use the same version of shared dependencies.
- Disadvantages:
- Dependency conflicts: If two packages require different versions of the same dependency, hoisting may not work as expected.
- Complexity: Dependency resolution can become more complex, especially when dealing with non-hoistable dependencies or version mismatches.
- Potential breakage: Packages may accidentally rely on dependencies that are hoisted but not explicitly declared in their
package.json
.
When to Use Each Approach
- Isolated
node_modules
:- Use when you need strict isolation between packages.
- Ideal for projects where packages have highly divergent dependencies or need to be deployed independently.
- Hoisted
node_modules
:- Use in monorepos or workspaces (e.g., with tools like Yarn Workspaces, Lerna, or PNPM) to optimize for disk space and installation speed.
- Ideal when packages share many dependencies and need to work together closely.
Tools That Support Hoisting
- Yarn Workspaces: Automatically hoists shared dependencies to the root
node_modules
. - PNPM: Uses a unique approach with a global store and symlinks, but also supports hoisting.
- Lerna: Can be configured to hoist dependencies in monorepos.
In summary:
- Isolated
node_modules
: Dependencies are installed per package, ensuring isolation. - Hoisted
node_modules
: Dependencies are shared and deduplicated at the root level, optimizing for space and speed.