Back to Scaling Node.js Applications guides

PNPM vs. Bun Install vs. Yarn Berry

Stanley Ulili
Updated on May 16, 2025

That node_modules folder is eating your disk space alive. Your CI pipeline spends more time installing dependencies than actually testing code. And somehow, after pulling in your colleague's changes, everything breaks because of a package conflict.

Sound familiar? JavaScript package management can be painful. But in 2025, you have options beyond the standard npm experience.

PNPM saves disk space by storing each package once globally. Version 10.11.0 supports JSR packages and smarter patching.

Bun Install is blisteringly fast—up to 30x faster than npm, cutting wait times from minutes to seconds.

Yarn Berry (v4+, "Yarn Modern") eliminated node_modules entirely with Plug'n'Play, enabling "zero installs"—clone and run immediately.

I'll compare these three alternatives to help you choose the right one for you.

What is PNPM?

Screenshot of PNPM Github page

PNPM (pronounced "p-n-p-m") is a package manager that saves disk space with a smart approach to node_modules.

Created by Zoltan Kochan in 2017 as an npm alternative, PNPM's big innovation is its content-addressable storage system. It stores all packages once in a global store and creates hard links to them in your project's node_modules. This cuts disk usage dramatically by not duplicating packages across projects.

Unlike npm or Yarn Classic, PNPM enforces a strict node_modules structure that matches your dependency tree. This prevents "phantom dependencies" where projects accidentally use packages they haven't declared. PNPM makes your projects more reliable by ensuring packages can only access what they've explicitly listed in package.json.

What is Bun Install?

Screenshot of Bun Github page

Bun Install is part of the Bun JavaScript runtime and toolkit. It focuses on making package installation incredibly fast.

Developed by Jarred Sumner in 2021, Bun Install uses the Zig programming language for maximum speed. Unlike npm or Yarn, which run on Node.js, Bun has its own JavaScript runtime and native package installer, making it much faster.

Bun Install gives you near-instant feedback when installing packages - often 20-30x faster than npm. It works with all npm packages while cutting out the startup and parsing slowdowns that plague JavaScript-based package managers. By 2025, Bun will have become stable enough for production use, with better mono repo support and integration with major development tools.

What is Yarn Berry?

Screenshot of Yarn Berry Github page

Yarn Berry is the modern version of the Yarn package manager (v2 and beyond). It completely reimagines how dependencies work by removing the node_modules folder.

Released in 2020 as a full rewrite of Yarn Classic, Yarn Berry replaces thousands of node_modules files with a single .pnp.cjs file that maps where packages are stored. This cuts down on disk operations and enables powerful features like zero-installs, where you can commit dependencies directly to git.

Beyond its Plug'n'Play (PnP) system, Yarn Berry offers a plugin system, interactive upgrade tools, and improved workspace features. It prioritizes performance and reliable builds. By 2025, Yarn has evolved to version 4+ (now called "Yarn Modern"), with faster performance, a new JavaScript-based constraints engine, and better integration with Node.js through Corepack.

PNPM vs. Bun Install vs. Yarn Berry: a quick comparison

Your choice of package manager affects development speed, project structure, and team productivity. Each package manager has distinct advantages depending on your project needs.

Here's how they compare on key features:

Feature PNPM Bun Install Yarn Berry
Core design philosophy Disk space efficiency with a content-addressable store Maximum speed through native implementation Reproducibility via Plug'n'Play architecture
Node_modules structure Symlinks to global store with strict dependency tree Compatible with npm but faster installation Replaces node_modules with .pnp.cjs file
Installation performance 2x faster than npm 20-30x faster than npm Similar to npm but with faster subsequent runs
Disk space usage Minimal through shared storage Standard (similar to npm) Varies (zero-install can increase repo size)
Monorepo support First-class workspaces with powerful filtering Basic workspace support Advanced workspaces with constraints
Dependency hoisting Disabled by default (strict node_modules) Compatible with npm hoisting Customizable through settings
Lockfile format pnpm-lock.yaml bun.lockb (binary format) yarn.lock with PnP metadata
Backward compatibility Requires adaptation for some packages High npm compatibility May require patches for PnP compatibility
Cache mechanism Content-addressable global store High-performance binary cache Sophisticated Zip-based cache
Plugin ecosystem Limited but growing Minimal (focused on core performance) Extensive and powerful plugin system
Offline support Strong with shared cache Good with local cache Excellent with zero-installs
IDE integration Requires configuration for strict mode Works with standard tooling Requires specific IDE extensions for PnP
Community size Growing rapidly Newest, but gaining traction Established with active migration to Modern
Current version 10.11.0 (May 2025) Latest binary (May 2025) 4.x (Yarn Modern)
Node.js requirements v18.12+ v18+ (minimum v5.1 Linux kernel) Supports all modern Node versions

Installation and setup

The way you get started with a package manager sets the tone for everything that follows. Each tool reveals its priorities in how it asks to be installed.

PNPM keeps it simple with a straightforward npm-based installation, making it an easy upgrade from npm:

 
# Install PNPM globally
npm install -g pnpm

# Initialize a new project
pnpm init

# Install dependencies
pnpm install

PNPM works with existing package.json files, so migrating from npm or Yarn is easy. When you first install it, PNPM creates a global store (usually in a .pnpm-store directory) where it keeps all packages.

Bun Install emphasizes its standalone nature with a quick installation process that shows off its speed right away:

 
# Install Bun globally (on macOS, Linux, or WSL)
curl -fsSL https://bun.sh/install | bash

# Initialize a new project
bun init

# Install dependencies
bun install

Bun's installation highlights how it differs from Node.js-based tools. Once installed, you'll notice that bun install finishes much faster than other package managers - often in a fraction of the time.

Yarn Berry takes a more deliberate approach, reflecting its big shift from Classic Yarn:

 
# Install Yarn globally if not already present
npm install -g yarn

# Set the version to Berry in an existing project
yarn set version berry

# Or initialize a new project with Berry
yarn init -2

# Install dependencies
yarn install

The yarn set version berry command transforms a project from Classic Yarn to Yarn Berry, replacing the traditional node_modules approach with Plug'n'Play.

This creates a .yarn folder for the release, plugins, and cache, plus a .pnp.cjs file that replaces node_modules functionality.

Each installation method shows the package manager's priorities: PNPM focuses on incremental improvement over npm, Bun emphasizes raw speed, and Yarn Berry commits to rethinking fundamental package management concepts.

Dependency management

Each package manager's approach to managing dependencies reveals fundamental differences that affect everything from disk usage to security.

PNPM uses a revolutionary storage system with a content-addressable store and hard linking to save disk space while ensuring dependencies work correctly:

 
# Installing a dependency with PNPM
pnpm add react

# Installing a dev dependency
pnpm add -D typescript

# Examining the strict node_modules structure
# node_modules contains only declared dependencies with symlinks to the global store

PNPM's structure prevents "phantom dependency" problems by ensuring packages can only access what they've explicitly declared. This strict approach sometimes requires configuration adjustments for packages used to npm's more permissive dependency resolution:

 
// .npmrc file for compatibility with packages that rely on hoisting
node-linker=hoisted

Bun Install focuses on speed while staying compatible with the npm ecosystem, making it an easy replacement:

 
# Installing a dependency with Bun
bun add react

# Installing a dev dependency
bun add -d typescript

# Bun creates a standard node_modules structure compatible with npm,
# but does so dramatically faster

Bun’s binary lockfile bun.lockb boosts performance, but it’s not human-readable like YAML. If you switch from npm, Bun will give you the smoothest path with almost no configuration changes:

 
# Converting an existing npm/yarn project to Bun
bun install

# This automatically generates the bun.lockb file while maintaining
# compatibility with your existing setup

Yarn Berry completely reimagines dependency management with its Plug'n'Play approach, replacing node_modules with a single resolution file:

 
# Installing a dependency with Yarn Berry
yarn add react

# Installing a dev dependency
yarn add -D typescript

# Instead of creating thousands of files in node_modules,
# Yarn Berry generates/updates a single .pnp.cjs file

This radical approach requires some adaptation, particularly for tools that expect traditional node_modules. Yarn Berry addresses compatibility through its plugin system and "fallback" modes:

 
// package.json configuration for better compatibility
{
  "packageManager": "yarn@3.5.0",
  "installConfig": {
    "pnp": false
  }
}

PNPM shines in disk space efficiency and dependency correctness, Bun delivers unmatched installation speed, and Yarn Berry offers an innovative dependency resolution approach enabling powerful features like zero-installs.

Monorepo support

Managing multiple packages in a single repository is common in modern JavaScript development. Each package manager handles this challenge differently.

PNPM offers excellent monorepo support through its workspace feature, with efficient tools for complex projects:

 
// pnpm-workspace.yaml
packages:
  - 'packages/*'
  - 'apps/*'
  - '!**/test/**'

PNPM's workspace commands include powerful filtering that makes working with specific packages easy:

 
# Install dependencies for all workspaces
pnpm install

# Run a script in a specific package
pnpm --filter package-name run build

# Add a dependency to a specific package
pnpm --filter package-name add lodash

# Run a command in all packages that depend on a specific package
pnpm --filter "...package-name" run test

PNPM's strict dependency management works especially well in monorepos, stopping packages from accidentally using dependencies from sibling packages they haven't declared. This enforced correctness makes large codebases more maintainable. As of 2025, PNPM's support for patching dependencies by version ranges gives you even more flexible control in monorepo environments.

Bun Install provides basic workspace support focused on performance rather than advanced filtering:

 
// package.json
{
  "workspaces": [
    "packages/*",
    "apps/*"
  ]
}

Working with Bun workspaces is simple and fast:

 
# Install all dependencies (extremely fast even in large workspaces)
bun install

# Run a script in a specific workspace
bun run --cwd packages/my-package build

# Add a dependency to a specific package
cd packages/my-package && bun add lodash

Bun's performance advantages really stand out in monorepos, where other package managers often slow down as you add more packages. By 2025, Bun has added better workspace filtering capabilities that make it competitive with other monorepo-focused tools while keeping its speed advantage.

Yarn Berry takes workspace management to the next level with advanced features like constraints, selective installs, and sophisticated dependency handling:

 
// package.json
{
  "workspaces": [
    "packages/*",
    "apps/*"
  ]
}

Yarn Berry offers unique workspace capabilities:

 
# Install all dependencies
yarn install

# Run a script in a specific workspace
yarn workspace package-name run build

# Add a dependency to a specific package
yarn workspace package-name add lodash

# Define constraints between workspaces
yarn constraints

The constraints feature is Yarn Berry's standout approach to monorepo management, letting you define and enforce rules across workspaces. In Yarn 4+, the constraints system has been rebuilt with a JavaScript-based engine replacing the previous Prolog implementation, making it easier to use:

 
// .yarn/constraints.js
module.exports = {
  // Ensure all packages use the same version of React
  constraints: async ({Yarn, Cache}) => {
    for (const workspace of Yarn.workspaces()) {
      for (const dependency of workspace.dependencies()) {
        if (dependency.name === 'react') {
          dependency.update('18.2.0');
        }
      }
    }
  }
};

PNPM excels with its powerful filtering syntax and disk efficiency, Bun shines through raw speed that becomes increasingly valuable as monorepos grow, and Yarn Berry offers the richest feature set with innovations like constraints and focus on reproducibility.

Caching and performance

How each package manager handles caching reveals key architectural differences that significantly impact performance and reliability.

PNPM's global store works as both a cache and storage optimization, creating a unique system that gets more efficient over time:

 
# The global store is automatically used and maintained
# You can view its location with:
pnpm store path

# You can clear it if needed:
pnpm store prune

This content-addressable store means once you've installed a package on your system, it never needs to be downloaded again for any project. PNPM simply creates hard links to the existing files, making subsequent installs nearly instant.

 
# Verify the store's integrity:
pnpm store status

# For teams, you can configure a shared store location:
# .npmrc
store-dir=/path/to/shared/store

PNPM's disk cache strategy makes it especially valuable when you have limited bandwidth or disk space constraints.

Bun Install uses an aggressive binary cache designed for maximum speed, reflecting its focus on performance above all:

 
# Clear Bun's cache if needed
bun pm cache rm

# Cache path can be configured in bunfig.toml
[install]
cache = "/custom/cache/path"

Bun's cache uses a custom binary format optimized for read/write performance rather than disk space efficiency. This design choice, combined with its native implementation, enables Bun's remarkable installation speeds:

 
# Bun's installation speed shines particularly in CI environments
# package.json
{
  "scripts": {
    "ci:install": "bun install --frozen-lockfile"
  }
}

CI pipelines can see dramatic improvements when switching to Bun, often cutting installation times from minutes to seconds.

Yarn Berry introduces a sophisticated caching system built around Zip files, enabling unique capabilities like zero-installs:

 
# Enable zero-installs to commit dependencies to version control
yarn config set enableGlobalCache false
yarn config set enableImmutableInstalls true

# The .yarn/cache directory will contain all dependencies as Zip files
# Add to version control to enable zero-installs

With zero installs, you can clone a repo and run the project immediately without waiting for dependencies to install.

 
# With zero-installs, this is essentially instant:
git clone project && cd project && yarn start

Yarn's ".yarn/cache" directory contains compressed versions of all dependencies, balancing performance and disk usage:

 
# For teams not using zero-installs, a shared cache can be configured:
yarn config set enableGlobalCache true
yarn config set globalFolder "/path/to/shared/cache"

PNPM optimizes for disk space efficiency with consistently good performance, Bun prioritizes raw speed with its revolutionary runtime approach, and Yarn Berry focuses on predictability and developer experience through features like zero-installs that eliminate waiting for dependencies.

Configuration and customization

A package manager’s extensibility reflects how it handles the trade-off between simplicity and advanced control.

PNPM offers straightforward configuration through .npmrc files, staying compatible with the npm ecosystem while adding unique options:

 
# .npmrc file
shamefully-hoist=true
strict-peer-dependencies=false
auto-install-peers=true
node-linker=hoisted

PNPM's configuration focuses mainly on controlling its unique dependency resolution behavior, with options to adjust hoisting behavior for compatibility with challenging packages:

 
# Create a project-specific configuration
pnpm config set --location=project save-exact true

# List current configuration
pnpm config list

In 2025, PNPM has expanded its configuration options with support for new settings like pnpm.allowUnusedPatches and pnpm.ignorePatchFailures to fine-tune patching behavior, and even supports environment variables in workspace settings:

 
# .npmrc
# Configure patch application failures
pnpm.ignorePatchFailures=false

# Support for JSR packages
@jsr:registry=https://npm.jsr.io/

Bun Install focuses on sensible defaults rather than extensive configuration, reflecting its focus on simplicity and performance:

 
# bunfig.toml
[install]
# Use exact versions in package.json
exact = true

# Create a node_modules directory
linkNodeModules = true

# Cache location
cache = "/path/to/cache"

Bun's configuration options are deliberately minimal, focusing on the most common customization needs while avoiding complexity:

 
# Configure Bun from the command line
bun pm config set registry https://custom-registry.com

# Authentication for private registries
bun pm login --registry=https://registry.npmjs.org

In 2025, Bun has added more configuration options for handling lifecycle scripts and private repositories while keeping its streamlined approach:

 
# bunfig.toml
[install]
# Automatically run any lifecycle scripts without whitelisting
dangerouslyAllowAllBuilds = true

# Configure CI-specific behavior
frozen = true

Yarn Berry embraces extensive customization through its plugin system, enabling powerful changes to its core behavior:

 
// package.json
{
  "packageManager": "yarn@4.0.0",
  "dependencies": {
    // Regular dependencies
  },
  "resolutions": {
    // Override specific nested dependencies
    "somePackage/problematicDependency": "1.2.3"
  }
}

Yarn's plugin system stands out as a unique strength, letting you extend core functionality:

 
# Add a plugin
yarn plugin import interactive-tools

# Plugin adds new commands like upgrade-interactive
yarn upgrade-interactive

In 2025, Yarn's configuration ecosystem has expanded with improved Corepack integration, enabling easier version management without checking in binaries:

 
# Enable Corepack (built into Node.js 16+)
corepack enable

# Set the project to use a specific Yarn version
yarn set version 4.0.0

# This creates/updates packageManager field in package.json
# Corepack will automatically use this version for all team members

PNPM offers focused configuration targeting its unique dependency model, Bun emphasizes minimal configuration with excellent defaults, and Yarn Berry provides the most extensible platform through its comprehensive plugin system.

Migration and compatibility

Switching between package managers involves different levels of effort depending on your starting point and destination, with each offering different compatibility guarantees.

PNPM maintains strong compatibility with the npm ecosystem while enforcing stricter dependency rules:

 
# Migrate from npm to PNPM
# (existing package.json and package-lock.json are preserved)
pnpm import

# The import command converts npm's lock file to pnpm-lock.yaml

The main compatibility challenge with PNPM involves packages that rely on npm's hoisted dependency structure, which you can fix through configuration:

 
# .npmrc
# Enable limited hoisting for problematic packages
shamefully-hoist=true

# For extreme cases, revert to npm-like hoisting
node-linker=hoisted

Migration to PNPM is typically straightforward for most projects, with compatibility issues mostly in packages with non-standard import patterns or those relying on implicit hoisting.

Bun Install offers the smoothest transition experience, deliberately maintaining maximum compatibility with npm:

 
# Migrate from npm/yarn to Bun
# (generates bun.lockb while preserving package.json)
bun install

# Bun can even use existing lockfiles to some extent
bun install --frozen-lockfile

Bun's approach prioritizes drop-in compatibility, with most projects requiring no configuration changes:

 
# Test compatibility by running scripts
bun run build

# If issues arise, you can always revert seamlessly
npm install

This compatibility-first approach makes Bun a great low-risk option if you want better performance without changing your workflow too much.

Yarn Berry requires the biggest migration effort because of its radical Plug'n'Play system.

 
# Migrate from Yarn Classic to Yarn Berry
yarn set version berry

# Import existing yarn.lock
yarn

The transition to PnP often requires configuration adjustments and occasionally patching packages:

 
# Add the compatibility plugin for easier migration
yarn plugin import @yarnpkg/plugin-compat

# For packages with compatibility issues, use patches
yarn patch-package problematic-package

Yarn Berry's .yarnrc.yml configuration provides options to ease migration:

 
# .yarnrc.yml
nodeLinker: pnp

pnpMode: loose

# For progressive migration
pnpFallbackMode: all

PNPM offers a balanced migration path with occasional configuration needs, Bun provides nearly seamless transition with excellent npm compatibility, and Yarn Berry requires more intentional migration but delivers unique benefits that may justify the effort.

Final thoughts

This article compared PNPM, Bun Install, and Yarn Berry to help you choose the right package manager for your JavaScript projects.

PNPM is known for saving disk space and enforcing strict dependency rules. It’s a solid choice if you work with large monorepos or care about reliability, and it now supports patching and JSR packages.

Bun Install stands out for its speed and smooth npm migration. It improves CI times and offers solid compatibility, monorepo support, and integration with modern development platforms.

Yarn Berry (now called Yarn Modern) takes a bold approach with Plug’n’Play, zero-installs, and a powerful plugin system, making it ideal for teams that value customization and innovation.

All three offer clear advantages over npm. Pick PNPM for efficiency and accuracy, Bun for performance, or Yarn for advanced features and flexibility.

Got an article suggestion? Let us know
Licensed under CC-BY-NC-SA

This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

Make your mark

Join the writer's program

Are you a developer and love writing and sharing your knowledge with the world? Join our guest writing program and get paid for writing amazing technical guides. We'll get them to the right readers that will appreciate them.

Write for us
Writer of the month
Marin Bezhanov
Marin is a software engineer and architect with a broad range of experience working...
Build on top of Better Stack

Write a script, app or project on top of Better Stack and share it with the world. Make a public repository and share it with us at our email.

community@betterstack.com

or submit a pull request and help us build better products for everyone.

See the full list of amazing projects on github