pnpm's node_modules structure is uniquely designed with three layers:
Directory Structure:
shellnode_modules/ ├── .pnpm/ # Stores actual content of all dependencies │ ├── lodash@4.17.21/ # Specific version of each package │ │ └── node_modules/ │ │ └── lodash/ # Hard link to global store │ └── express@4.18.2/ │ └── node_modules/ │ ├── express/ # Hard link │ └── ... # Dependencies of dependencies ├── .modules.yaml # pnpm metadata └── lodash -> .pnpm/lodash@4.17.21/node_modules/lodash # Symlink
Three-Layer Structure Analysis:
-
node_modules/[package]
- Symlinks pointing to actual packages in .pnpm directory
- Only contains direct dependencies, avoiding phantom dependencies
-
node_modules/.pnpm/[package@version]
- Contains actual content of each package version
- Uses hard links pointing to global store
-
Global store (~/.pnpm-store)
- All packages stored only once across all projects
- Content-addressable storage
Design Advantages:
javascript// ❌ In npm/Yarn you can access like this (phantom dependency) import lodash from 'lodash' // Even if not declared in package.json // ✅ In pnpm only declared dependencies are accessible // Undeclared dependencies cannot be accessed, safer
Key Features:
- Strict dependency isolation
- Prevents access to undeclared dependencies
- Proper peer dependencies resolution
- Better package version management