10 minutes read

Why Do I Love pnpm?

Have you ever felt bogged down by the installation process, storage, and security issues in your projects? Well, worry no more, because I've discovered a game-changing package manager called pnpmΒ (opens in a new tab) that has made my life so much easier!

In the world of Node.js, package managers play a crucial role in simplifying and managing the installation of dependencies. You might have heard of popular package managers like npm and yarn, but today, I'm going to focus on the rising star that is pnpm. It boasts some incredible features that have made me fall head over heels in love with it, and I bet you'll feel the same way after diving into this article! So, buckle up and get ready to learn all about the awesome world of pnpm through my personal experience!

The benefits of pnpm

Alright, let's dive right into the fantastic benefits of pnpm that have truly won me over!

Efficient storage and installation

  • Symlinking strategy for node_modules: pnpm creates a global content-addressable store of package files on your computer. Instead of copying packages into each project's node_modules folder, it creates hard links or symlinks pointing to the global store. This strategy significantly reduces duplicate package files and conserves disk space. Plus, it ensures a cleaner workspace with fewer files to sift through!
  • Reduced storage footprint: The symlinking strategy employed by pnpm considerably reduces the storage space needed for dependencies. This efficient system ultimately leads to faster and more responsive file operations, making development smoother and more enjoyable.

Faster installations

  • Parallel package installation: pnpm's installation process benefits from concurrency, which means it can download, extract, and link multiple packages simultaneously. This parallelism drastically reduces the time spent waiting for packages to be installed, letting you dive into coding much quicker. Don't believe me? Check the benchmarksΒ (opens in a new tab)!
  • Smarter download strategy: pnpm caches downloaded packages in its global store, enabling it to reuse them across projects. If a package is already available in the store, pnpm skips downloading it again. This approach minimizes redundant downloads, further speeding up the installation process.

Enhanced security

  • Strict package resolution: pnpm uses a strict package resolution algorithm, which means it always installs the exact package version specified in your package.json or lockfile. This deterministic behavior minimizes the risk of unintentionally introducing security vulnerabilities or breaking changes in your projects.
  • Protection against malicious scripts: pnpm isolates packages from one another by default, meaning a package cannot access the files of another package unless explicitly allowed. This isolation significantly reduces the chances of a malicious package affecting your projects or running harmful post-install scripts.

pnpm's unique features

Now that we've explored the fantastic benefits of pnpm, it's time to dive into some of the unique features that make it truly stand out from the crowd!

Workspaces

  • Easy management of monorepos: pnpm's workspaces feature makes managing monorepos a breeze! It allows you to work with multiple projects under a single repository, streamlining dependency management across these projects. With pnpm, you can efficiently update, test, and maintain all packages in a monorepo without any hassle.
  • Simplified dependency management: With workspaces, pnpm enables simplified dependency management across your projects. It lets you share dependencies across packages, keeping your lockfiles lean and your monorepo organized. pnpm also allows you to run scripts across all workspace packages with just a single commandβ€”talk about a time-saver!

Suppose you have a monorepo with three packages: frontend, backend, and shared.

Your directory structure might look like this:

my-monorepo/
β”œβ”€ frontend/
β”‚  β”œβ”€ package.json
β”‚  └─ ...
β”œβ”€ backend/
β”‚  β”œβ”€ package.json
β”‚  └─ ...
β”œβ”€ shared/
β”‚  β”œβ”€ package.json
β”‚  └─ ...
└─ package.json

To configure pnpm workspaces, you'll need to create a "pnpm-workspace.yaml" file in the root of your monorepo:

pnpm-workspace.yaml
packages:
  - "frontend"
  - "backend"
  - "shared"

Now, let's say the frontend and backend packages depend on the shared package, and all three packages depend on lodash. You can define the shared package as a local dependency and lodash as a common dependency in the root package.json file:

package.json
{
  "name": "my-monorepo",
  "private": true,
  "dependencies": {
    "lodash": "^4.17.21",
    "shared": "workspace:*"
  }
}

By specifying the "shared" dependency with the "workspace:*" version, pnpm knows to symlink the local shared package in the node_modules folder of both frontend and backend. The lodash dependency will be installed in the root node_modules folder and symlinked into frontend, backend, and shared folders.

Selective dependency resolutions

  • Improved control over dependencies: pnpm's selective dependency resolution gives you more control over your project's dependencies. This feature allows you to define custom resolution strategies for specific packages, helping you to handle edge cases, work around known issues, or even test a new version of a package without updating the entire dependency tree.
  • Resolution strategies for edge cases: In certain situations, you might need to install a specific package version that isn't compatible with your project's dependency tree. pnpm's selective dependency resolution allows you to do just that, offering you the flexibility to manage complex scenarios without compromising the integrity of your project.

For example, imagine you have a project with the following dependencies in your package.json:

package.json
{
  "dependencies": {
    "package-A": "1.0.0",
    "package-B": "2.0.0"
  }
}

Package-A has a dependency on package-X version 1.0.0, and package-B has a dependency on package-X version 1.1.0. However, you've discovered that there's an issue with package-X version 1.1.0, and you want to use version 1.2.0 instead.

With pnpm's selective dependency resolution, you can create an "overrides" section in your package.json file to specify custom resolutions for specific packages:

package.json
{
  "dependencies": {
    "package-A": "1.0.0",
    "package-B": "2.0.0"
  },
  "pnpm": {
    "overrides": {
      "package-X@1.1.0": "1.2.0"
    }
  }
}

CLI usability and extensibility

  • Intuitive command-line interface: pnpm's command-line interface (CLI) is designed with usability in mind. It provides easy-to-understand commands, detailed help output, and useful error messages, making it a joy to work with. Plus, it's compatible with most npm commands, so there's little to no learning curve for developers already familiar with npm.

  • Command autocomplete: pnpm's command-line interface (CLI) supports autocomplete, which helps you quickly find and use the commands you need. This feature speeds up your workflow and reduces the chances of making mistakes.

    To enable autocompletion, simply run the following command:

    pnpm install-completion

    Now, when you start typing a command in your terminal (e.g., pnpm i), you can press the "Tab" key to see suggestions for available commands (e.g., pnpm install, pnpm init, etc.).

Environment management

  • Simplified Node.js version management: pnpm has an impressive built-in feature to manage multiple Node.js versions, eliminating the need for additional tools like nvm. By using the 'pnpm env use' command followed by the desired Node.js version, you can effortlessly switch between different environments for your projects.
  • Consistent project environments: Managing your Node.js versions with pnpm ensures a consistent environment across your projects. It maintains a separate global store for each Node.js version, preventing any potential compatibility issues between projects. This consistent environment management contributes to a more stable and streamlined development experience.

Suppose you have two projects, Project-A and Project-B, that require different Node.js versions (v14.0.0 and v16.16.0, respectively). With pnpm, you can manage these environments without relying on external tools like nvm.

Simply create a .npmrc file in each project's and add a "use-node-version" field specifying the required Node.js version. Here's an example for Project-B:

.npmrc
use-node-version=16.16.0

By doing so, pnpm will automatically install the specified version of Node.js and use it for running pnpm run commands or the pnpm node command.

pnpm vs. npm

  • Disk space efficiency: Unlike npm, which duplicates packages across projects, pnpm's symlinking strategy dramatically reduces disk space usage. This efficient approach not only saves storage but also results in faster file operations.
  • Parallel package installation: pnpm's ability to download, extract, and link packages concurrently gives it an edge over npm, which installs packages sequentially. This parallelism leads to significantly faster installation times.
  • Enhanced security: pnpm's strict package resolution and isolation between packages ensure a safer development environment compared to npm. These features help minimize the risk of introducing security vulnerabilities or executing malicious scripts.

pnpm vs. yarn

  • Storage efficiency: Similar to yarn, pnpm uses a global store to manage packages. However, pnpm goes a step further by using hard links or symlinks to share packages between projects, which results in even greater storage efficiency.
  • Workspaces: Both pnpm and yarn support workspaces for managing monorepos. While their implementations are quite similar, pnpm stands out with its simplified dependency management, allowing you to share dependencies across packages more effectively.
  • Environment management: Unlike yarn, pnpm has built-in support for managing multiple Node.js versions. This feature simplifies your development workflow by eliminating the need for external tools like nvm, giving pnpm an advantage in terms of environment management.

Wrapping Up

From its efficient storage and lightning-fast installations to its enhanced security and unique features, pnpm has truly revolutionized the way I manage dependencies in my projects.

Whether you're working on a simple project or managing a complex monorepo, pnpm has something to offer for everyone. Its numerous benefits, coupled with its compatibility with popular package managers like npm and yarn, make it an excellent choice for developers looking to elevate their workflow.

So why not give pnpm a try in your next project? You may just find yourself falling in love with it, just as I have. Here's to more efficient, secure, and enjoyable development experiences with pnpm! πŸš€πŸŒŸ