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.lock for integrity verification
  • npm: npm audit for vulnerability scanning (both tools now have good security features)

Caching:

  • Yarn: Global cache by default at ~/.yarn/cache
  • npm: Uses cache at ~/.npm with 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!

Resources: