So I’ve read that Yarn is faster than npm install so thought I’d try it out.
I mean of course this project is tiny but can I see a difference, even slightly… 👀
Background context: Yarn was created by Facebook (now Meta) in 2016 to address several limitations in npm at the time, particularly around performance, security, and deterministic installs. While npm has significantly improved since then, there are still some key differences worth understanding.
Package installs
Maybe a bit faster? 🥸
npm install:
➜ ✗ npm install | gnomon
25.9102s
0.0001s added 2372 packages, and audited 2373 packages in 26s
Total 26.0307s
yarn install:
➜ ✗ yarn install | gnomon
0.2370s [1/4] Resolving packages...
0.3701s [2/4] Fetching packages...
7.8469s [3/4] Linking dependencies...
12.7897s [4/4] Building fresh packages...
0.0102s success Saved lockfile.
0.0064s Done in 21.32s.
0.0001s
Total 21.3360s
Analysis: Yarn was about 18% faster (21.3s vs 26.0s) in this test. The time difference comes from:
- Parallel downloads - Yarn downloads packages in parallel while npm (in older versions) was more sequential
- Global caching - Yarn uses a global cache to avoid re-downloading packages
- Optimized dependency resolution - Yarn’s algorithm is more efficient for resolving dependency trees
Building
Ok so nothing really happening here in terms of differences, but then again probably a tiny project to test with. 🤣
yarn build:
➜ ✗ yarn run build | gnomon
Total 16.3593s
npm build:
➜ ✗ npm run build | gnomon
Total 16.3904s
Analysis: Build times are essentially identical (16.36s vs 16.39s) because both package managers are just executing the same build script. The run command performance is similar since it’s just spawning the same underlying processes.
Key Technical Differences
Lockfiles:
- npm:
package-lock.json(introduced in npm 5.0) - Yarn:
yarn.lock - Both ensure deterministic installs, but with slightly different formats
Workspaces:
- Yarn: Native workspace support from the beginning
- npm: Added workspace support in npm 7.0
- Both support monorepo management now
Security:
- Yarn: Checksums in
yarn.lockfor integrity verification - npm:
npm auditfor vulnerability scanning (both tools now have good security features)
Caching:
- Yarn: Global cache by default at
~/.yarn/cache - npm: Uses cache at
~/.npmwith different strategy - Both use symlinks and hardlinks for efficiency
Conclusion 🐒
Ja, reading the docs, Yarn seems to be optimized for downloading and caching every package it has downloaded, so in theory if I restore another project on the same machine it should be faster since fewer network requests right, maybe?
What I discovered:
About gnomon: I learnt there is an awesome package called gnomon (pronounced “no-mon” 🤓) which can be used for timings with piping on unix. Super handy for benchmarking command-line operations!
About package managers: Well, I don’t understand package managers very well yet, but here’s what I’m curious about:
How they work under the hood 🧐
- Dependency resolution algorithms - How do they handle version conflicts?
- Network optimization strategies - Parallel downloads, compression, CDN usage
- File system optimizations - Symlinks, hardlinks, deduplication strategies
- Cache invalidation - When and how do they know to refresh cached packages?
- Security models - How do they verify package integrity and handle compromised packages?
Modern considerations (2024 perspective):
- pnpm has emerged as another alternative with even better disk space efficiency
- npm has significantly improved since Yarn’s initial release
- Bun is a new JavaScript runtime with its own package manager
- Package managers are converging - many features that made Yarn special are now in npm too
I am curious how it works under the hood and definitely want to dive deeper into the architectural design choices that spawned these different package managers. This is definitely on my learning roadmap!