JavaScript/Node Package Managers The Complete, HandsOn Guide (npm Yarn pnpm Bun)
In this article
- 11) What does a package manager do
- 22) Options at a glance
- 33) Core concepts (that apply to all)
- 44) npm -- the reliable default
- 55) Yarn -- Classic vs Berry
TL;DR Summary
-
npm best default: simple, builtin, reliable workspaces.
-
pnpm fastest + most spaceefficient for big monorepos; strict linking.
-
Yarn Berry PnP (no
node_modules) + zeroinstall; powerful but opinionated. -
Yarn v1 legacy, fine to maintain, but new features are in Berry.
-
Bun very fast, integrated runtime/tester; ecosystem still maturing.
Commit one lockfile. Pin Node & tool versions. Use workspaces. Enforce overrides/resolutions. Use ci/immutable installs in CI.
1) What does a package manager do
-
Resolves dependency versions from
package.json(incl. transitive deps). -
Writes a lockfile for reproducible installs.
-
Installs packages into
node_modules(or a virtual FS in Yarn PnP). -
Exposes project CLIs via
node_modules/.bin/. -
Supports workspaces/monorepos.
-
Talks to an npm registry (public/private) with auth, caching, proxies.
2) Options at a glance
| Manager | Lockfile | Install model | Workspaces | Superpowers | Tradeoffs |
|---|---|---|---|---|---|
| npm | package-lock.json |
Classic node_modules |
Yes (v7+) | Ubiquitous, easy, 1stparty, good defaults | Not the absolute fastest; fewer monorepo niceties than pnpm |
| Yarn v1 (Classic) | yarn.lock |
Classic node_modules |
Yes | Battletested; common in older monorepos | Legacy; new work focuses on Berry |
| Yarn Berry (v2+) | yarn.lock |
PnP (or nodemodules via plugin) | Yes | Zeroinstall, constraints, plugins, very fast | PnP may break tools that expect node_modules; learning curve |
| pnpm | pnpm-lock.yaml |
Linked node_modules from contentaddressable store |
Yes | Diskefficient, fast, strict, great filters | Some tools assume flat hoisting; needs tweaks |
| Bun | bun.lockb |
Classic node_modules |
Basic | Blazing fast + runtime/test | Binary lockfile; ecosystem still maturing |
Managerofmanagers: Corepack (bundled with Node 16.17) pins Yarn/pnpm versions via packageManager in package.json.
3) Core concepts (that apply to all)
-
Lockfile Deterministic graph; must be committed.
-
Hoisting Flatten deps to toplevel; convenient but can mask duplication.
-
Peer deps Required by consumers; misaligned peers cause install errors.
-
Overrides/Resolutions Force versions of nested deps (npm/pnpm:
overrides, Yarn:resolutions). -
Workspaces Single repo, many packages, one lockfile; local linking.
-
Scripts
npm run,yarn,pnpmexpose CLIs from.bin. -
Corepack Declares & provisions Yarn/pnpm versions per project.
4) npm -- the reliable default
Why npm
-
Ships with Node, minimal friction, strong CI/Docker ergonomics.
-
Modern npm supports workspaces, peerdep autoinstall,
overrides.
Common commands
npm i # install
npm ci # clean, lockfileonly install for CI
npm run -ws build # run script in all workspaces
npm run build -w pkg # run in one workspace
npm outdated && npm audit
Helpful snippets
// package.json (excerpt)
{
"private": true,
"workspaces": ["apps/*", "packages/*"],
"engines": { "node": ">=20 <21" },
"packageManager": "npm@10"
}
# .npmrc
engine-strict=true
fund=false
audit=true
// npm overrides
{
"overrides": {
"ansi-regex": "6.0.1",
"react-dom@^18": "18.3.1"
}
}
5) Yarn -- Classic vs Berry
Yarn v1 (Classic)
-
Familiar
node_moduleslayout, workspaces OK. -
Good for maintaining existing repos without big changes.
Yarn Berry (v2+)
-
PnP: virtual filesystem; optionally switch to
node-moduleslinker. -
Zeroinstall: commit
.yarn/cacheto avoid network in CI. -
Plugins: Constraints, version policies, interactive upgrades.
Berry basics
# .yarnrc.yml
nodeLinker: pnp # or 'node-modules'
yarnPath: .yarn/releases/yarn-4.x.cjs
npmRegistryServer: https://registry.npmjs.org/
// package.json
{ "resolutions": { "left-pad": "1.3.0" } }
yarn install --immutable
# Run in all workspaces
yarn workspaces foreach -A run build
6) pnpm -- fast & spaceefficient
Why pnpm
-
Contentaddressable store + symlinked
node_modulessaves disk. -
Strict linking catches phantom deps early.
-
Excellent monorepo filters & commands.
Workspace setup
# pnpm-workspace.yaml
packages:
- "apps/*"
- "packages/*"
# .npmrc (pnpm respects many npmrc keys)
shamefully-hoist=false
strict-peer-dependencies=true
pnpm install
pnpm -r build # recursive in all packages
pnpm -F @scope/pkg test # filter target
pnpm prune --prod
7) Bun -- speed + allinone runtime
-
bun installis very fast; lockfile is binary (bun.lockb). -
Bundled test runner & runtime -- great for prototypes/greenfield.
-
Ensure ecosystem tools (plugins/CLIs) behave as expected.
bun install
bun run build
8) CI/CD recipes (copypaste friendly)
GitHub Actions -- npm
- uses: actions/setup-node@v4
with: { node-version: '20', cache: 'npm' }
- run: npm ci
- run: npm run -ws build --if-present
- run: npm test --workspaces --if-present
GitHub Actions -- pnpm
- uses: actions/setup-node@v4
with: { node-version: '20', cache: 'pnpm' }
- run: corepack enable
- run: pnpm install --frozen-lockfile
- run: pnpm -r build
GitHub Actions -- Yarn Berry
- uses: actions/setup-node@v4
with: { node-version: '20' }
- run: corepack enable
- run: yarn install --immutable
- run: yarn workspaces foreach -A run build
9) Docker patterns (prodready)
Builder Runtime (npm)
FROM node:20 AS deps
WORKDIR /app
COPY package.json package-lock.json ./
COPY packages/*/package.json apps/*/package.json ./
RUN npm ci --include-workspace-root
FROM node:20 AS build
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run -ws build
FROM node:20-slim
WORKDIR /app
COPY --from=build /app .
RUN npm prune --omit=dev
CMD ["node","apps/api/dist/main.js"]
Yarn Berry: copy
.yarn+yarn.lock, useyarn install --immutable.
pnpm: install via Corepack and usepnpm-lock.yaml.
10) Migration playbooks
Yarn v1 npm
-
Replace
yarn <script>withnpm run <script>. -
Convert
resolutionsnpmoverrides. -
Generate fresh
package-lock.jsonwithnpm ci.
npm pnpm
-
Add
pnpm-workspace.yaml. -
Fix peerdep warnings; avoid assuming flat hoist.
-
Use
pnpm install --frozen-lockfilein CI.
Yarn v1 Yarn Berry
-
Add
.yarnrc.yml+ choosepnpornode-moduleslinker. -
(Optional) Enable zeroinstall by committing
.yarn/cache. -
Patch tools that expect
node_modulesor switch to nodemodules linker.
11) Troubleshooting cookbook
-
Peer dependency conflict Align at the top level or use overrides/resolutions.
-
Lockfile merge hell Reinstall from clean tree; avoid manual edits; regenerate.
-
EAI_AGAIN / network flakiness Use registry mirrors/caching; Yarn zeroinstall; pnpm store.
-
Native addon fails on new OS/arch Reinstall on target OS; don't copy
node_modulesacross OSes. -
Tool mismatch Enforce via
packageManager+ apreinstallguard.
Preinstall guard (enforce npm only)
{
"scripts": {
"preinstall": "node -e \"const ua=process.env.npm_config_user_agent||''; if(!ua.startsWith('npm/')){console.error('Use npm only.'); process.exit(1)}\""
}
}
12) Security & compliance
-
Use scoped tokens in CI; never commit secrets.
-
Enable 2FA on registry accounts.
-
Regularly audit (
npm audit,pnpm audit,yarn npm audit). -
Pin critical transitive deps via overrides/resolutions.
-
Mirror or proxy registry (Verdaccio/Artifactory) for availability & provenance.
13) FAQ (quick hits)
-
Should I commit
node_modulesNo. Commit only the lockfile. -
One repo, many packages Use workspaces (npm/pnpm/Yarn all support).
-
Which is fastest pnpm/Yarn Berry are typically faster; Bun is very fast too.
-
Which is safest for a broad team npm or pnpm.
-
Can I mix managers Avoid mixing; enforce a single tool per repo.
14) Glossary
-
Lockfile: Snapshot of exact versions for reproducibility.
-
Hoisting: Lifting nested deps to toplevel
node_modules. -
Peer dependency: A dep you must install at the app level for a package to integrate correctly.
-
PnP: PlugandPlay; Yarn's virtual filesystem that replaces
node_modules. -
Corepack: Node helper that provisions Yarn/pnpm per project.
15) Onepage team checklist
-
Choose: npm / pnpm / Yarn Berry (document why).
-
Pin Node & tool via
engines+packageManager. -
Commit one lockfile at repo root.
-
Use workspaces with a single graph.
-
CI uses
ci/immutable/--frozen-lockfileinstalls. -
Use overrides/resolutions (never patch inside
node_modules). -
Regular audits; track advisories.
-
Production images prune dev deps.
-
Document commands for devs & CI.
Final take
For most teams: start with npm for simplicity, or pnpm for efficiency at scale. If you want PnP/zeroinstall and can accommodate it, Yarn Berry is excellent. Whatever you choose, lock it down (versions + lockfile), automate CI, and keep the graph healthy with audits and overrides.
Was this article helpful?
Your feedback helps us improve our documentation
Still need help? Submit a support ticket