Software

What Is pnpm? How Is It Different From npm and Yarn?

Talha Aslan 15 min read 1 views

What Is pnpm?

Pnpm is a package manager for JavaScript and Node.js projects that stores packages once in a shared content-addressable store and links them into each project with hard links, which saves disk space and makes dependency resolution stricter than npm or Yarn.

At Talha Aslan and his team, we often compare setup time and disk usage across custom software projects, and pnpm usually stands out. However, the right choice always depends on project size, team habits, and the existing toolchain. So before we go further, let's recall how npm and Yarn work.

Npm and Yarn Classic copy dependencies into a fresh node_modules folder for every project. Pnpm, instead, never writes the same package version to disk twice. It links to the file in the central store. As a result, the gap grows wider as more projects run on the same machine.

Why Was pnpm Created?

The pnpm project started as an answer to a simple cost: npm re-downloads and re-copies dependencies for every project, which wastes disk space and time. The official pnpm documentation states that the goal was to keep package files in one content-addressable store and link projects to it.

So a package at a given version no longer needs to be written to disk for dozens of projects. Moreover, if a new version differs from the old one by only a few files, pnpm adds only the changed files to the store. The rest already live there.

Additionally, npm and Yarn Classic flatten node_modules into a single level, and that habit let code reach packages the project never declared in package.json. The pnpm team treated this as a design flaw and built a different folder structure instead.

How Does pnpm's Storage Model Work?

Installation runs in three stages: first it resolves dependencies and fetches them into the central store, then it calculates the node_modules structure, and finally it links the stored files into the project with hard links. The official docs describe this order as faster than the classic resolve, fetch, and write flow.

The store lives on a single drive, and each package version sits there exactly once. When a new project needs the same version, the tool links to the existing copy instead of downloading it again. Consequently, network traffic drops too, because the package already sits in the local store.

The store and your projects should live on the same disk and file system. Otherwise the tool has to copy files instead of linking them, and the saving shrinks. We recommend keeping this in mind when you set up a CI/CD server.

Symlinks vs. Hard Links: What Is the Difference?

A hard link acts like a second name pointing at the same file on disk. The content exists once, yet several folders can reach it. A symlink, on the other hand, works like a shortcut that points to the real file's path.

This tool hard-links the real package files from the store into each project, then weaves the node_modules folder structure with symlinks. Direct dependencies sit at the root as symlinks, and those symlinks point to the real folders inside node_modules/.pnpm.

On Windows, when Developer Mode is off, the tool uses junctions instead of symlinks. That keeps the same logic working on the Windows file system. So the platform difference stays invisible to the end user.

How Does pnpm Save Disk Space?

With npm, ten different projects using the same package copy that package to disk ten times. With this tool, the same package sits in the store once, and all ten projects link to that single copy. As a result, total disk usage drops noticeably.

Teams running many small projects, or a monorepo, notice this saving first. A monorepo's own structure is a separate topic. We already covered it in our guide on what a monorepo is, so we won't repeat it here.

Also, when only a few files change between two versions of a package, the store adds just those changed files. The rest already live there, so they take no extra space the second time.

How Is the node_modules Structure Different From npm and Yarn?

Npm and Yarn Classic flatten every dependency, direct and indirect, into the root of node_modules. This tool, instead, places only the project's direct dependencies, the ones declared in package.json, at that root by default.

Indirect dependencies live as real files inside the internal node_modules/.pnpm folder, and the root-level packages point to that folder with symlinks. So the structure is not deeper. It just follows a flat yet layered logic.

  • Npm and Yarn Classic build a single, flattened node_modules.
  • This tool keeps only direct dependencies at the root. Real files live under .pnpm.
  • If your tooling cannot handle symlinks, you can switch the nodeLinker setting to hoisted and get an npm-like flat layout.

What Is the Phantom Dependency Problem?

A phantom dependency is a package your project never declared in package.json, yet your code can still import it. The flattened node_modules in npm and Yarn places that package at the root, so your code reaches it without noticing anything unusual.

The problem shows up later: that package is really an indirect dependency of a library you do use. If you remove or update that library, your project can suddenly break, because you never asked for the phantom package directly anywhere.

This tool's default node_modules structure blocks root-level access to undeclared packages. So when you first install a project with it, you might see a "module not found" error that uncovers one of these hidden dependencies. That is the strict design working as intended, not a bug.

Why Is pnpm Stricter About Dependency Resolution?

The official FAQ notes that the flat node_modules in npm and Yarn hides a common mistake: a project can use a package it never declared, and nobody notices. This tool makes that mistake visible instead of hiding it.

If a project breaks after switching because of one of these hidden dependencies, the docs suggest three fixes: add the missing package directly with the add command, switch nodeLinker to hoisted for an npm-like flat layout, or use a .pnpmfile.mjs readPackage hook to add the missing dependency to a package's manifest.

This strictness feels like extra work at first, but it shows exactly which packages your project truly depends on. The team can then manage the dependency tree with far more confidence.

Where Do You Start With Installation?

You can enable this tool through Corepack, which ships with Node.js, or install it globally through npm. Either path makes the command available in your terminal.

After that, the first step in an existing project is running the install command. It resolves dependencies, fetches them into the store, and links node_modules with hard links. If you are starting a new project, the init command creates a basic package.json for you.

Everyone on the team should use the same version. Otherwise the lockfile can produce different results on different machines. So pinning the version number in a project file keeps the whole team consistent.

If your network is slow, or your company uses a private registry, you need to set that in the tool's own config file. Otherwise packages try to come from the public registry instead.

Where You Start Verifying a Fresh Setup

To confirm installation worked, check the version in your terminal, then try the install command on a small test project. If the command finishes without errors and node_modules appears in the expected shape, the setup is healthy.

If you do see an error, first check your network connection, then check the registry setting in your config file. That combination resolves most setup issues quickly.

pnpm vs. Npm: What Are the Main Differences?

Placing the two tools side by side makes the differences clearer. The table below summarizes the points teams ask about most often.

FeatureNpmpnpm
StorageSeparate copy per projectOne shared store, hard links
node_modules rootFlattens every packageDirect dependencies only
Phantom dependenciesUsable without noticeBlocked by default
Lockfilepackage-lock.jsonpnpm-lock.yaml
Monorepo supportBasic, via workspaces fieldBuilt in, via pnpm-workspace.yaml

Command names mostly stay the same. Install, add, and run largely match their npm counterparts. So the learning curve for a team is usually shallow.

pnpm vs. Yarn: What Is the Difference?

Yarn Classic flattens node_modules in a way similar to npm. The newer Yarn releases (Berry) instead follow their own Plug'n'Play model. This tool keeps its own symlink-based model, separate from both approaches.

For disk savings, the shared store model beats Yarn Classic's habit of keeping a separate copy per project. Yarn Berry's Plug'n'Play model also removes most of node_modules, but it can need extra configuration for some tools to work.

Which one fits your team depends on how well your other tools support symlinks or Plug'n'Play. So we recommend testing the switch on a small pilot project first.

What Are pnpm Workspaces, and How Do They Support a Monorepo?

Workspaces let you group several packages in one repository and install them together. This is the tool's built-in monorepo support. It is based on a pnpm-workspace.yaml file at the project root.

The file lists the folder patterns where packages live, for example packages/*. If a project already uses the workspaces field from npm, Yarn, or Bun, and no pnpm-workspace.yaml exists yet, running install creates one with the same patterns automatically. It never overwrites an existing file.

  • The workspace: protocol guarantees that one package links to another local package.
  • When a package gets packed or published, the tool rewrites workspace: references into normal version ranges.
  • Thanks to the shared lockfile setting, the team manages the whole workspace through one pnpm-lock.yaml file.

We already cover the pros and cons of a monorepo itself in our monorepo guide. Here we only touch on how this tool supports that structure.

What Does the pnpm-lock.yaml File Do?

The lockfile records the exact version and dependency tree of every package your project installed. When the team shares this file, everyone's machine installs the same versions, which largely removes the classic "it works on my machine" problem.

You should commit this file to version control. Otherwise each developer can end up with a different dependency tree. A CI/CD server typically installs the exact versions from the lockfile too, so the build environment matches the local one.

We do not recommend editing the lockfile by hand. Instead, use the add, update, or remove commands to keep the file current. A manual edit can break the structure the tool expects and cause the next install to fail.

During code review, it is worth checking lockfile changes too. An unexpected version bump often signals that someone ran the wrong command, or that a hidden dependency just updated on its own. A small review habit catches a big version mismatch early.

How Do You Move From Npm or Yarn to pnpm?

This tool offers an import command that generates a pnpm-lock.yaml from an existing package-lock.json, npm-shrinkwrap.json, or yarn.lock file. The command reads the version data from the old lockfile and converts it into the tool's own format.

  1. Install the tool in your project, then run the import command.
  2. If your project is a workspace (monorepo), define pnpm-workspace.yaml before you import. Otherwise workspace packages' dependencies get left out.
  3. Run the install command and confirm node_modules builds as expected.

After migrating, you can delete the old package-lock.json or yarn.lock file. However, keeping both around for a while, until the whole team has switched, makes it easier to roll back if needed.

What Should You Watch for During Migration?

The most common issue during migration is the phantom dependency we described earlier: a project can suddenly throw a "module not found" error. In that case, you simply add the missing package to package.json directly.

Second, pay attention to where the store lives. If the store is not on the same drive as the project, the tool has to copy files instead of linking them, and your expected disk saving shrinks. So checking the drive setting matters early on.

Third, check the caching step in your CI/CD pipeline. If you never cache the store, every build re-downloads packages. If you manage your Node.js app on a server with pm2, we recommend settling this setting early in that same environment.

Which Projects Benefit Most From pnpm?

Teams running many Node.js projects on the same machine, or the same CI server, notice the disk saving first. Teams building a monorepo also get a built-in solution through workspaces.

For a small, one-off script, switching tools usually is not necessary. Your existing npm setup can stay just fine. If your team is setting up a custom project environment and wants outside support with that process, you can look into our custom software development service.

For teams working with TypeScript, the package manager choice also depends on compatibility with your build tools. We covered that comparison separately in our TypeScript vs. JavaScript guide.

Agencies and consultancies running many client projects at once see a clear benefit too. Most of the dependencies overlap across projects even when each client sits in its own folder, so one shared store removes a lot of duplication. A freelance developer keeping dozens of old projects on one laptop can feel a similar gain on their own.

Students running small experiments benefit from the switch as well. Once you understand the store's logic, grasping how dependency management works under the hood gets easier, and that understanding helps no matter which tool you use later.

Does pnpm Have Any Downsides?

The most common complaint is that some older tools do not work well with a symlink-based node_modules. They expect a flat folder and can throw errors when they do not find one.

In that case, you can switch nodeLinker to hoisted and get an npm-like flat layout. However, that choice also means giving up part of the strict dependency checking. Every setting involves some trade-off.

Also, everyone on the team needs to switch to the same package manager. If one person uses npm and another uses this tool, lockfiles can conflict. So we recommend making the switch decision together as a team.

Community resources and third-party tutorials still skew toward npm, since it has the larger audience. So finding a solution for an obscure error message can take a little longer. Following the official docs and community discussion boards closely largely makes up for that gap, and having at least one team member who knows these resources well gives everyone else a quick reference point.

How Different Are pnpm Commands From Npm?

Day to day, commands like install, add package-name, and run script-name work with largely the same logic as their npm counterparts. Because the command names are shorter, some teams find this tool more convenient.

The difference shows up in what happens behind the scenes: npm install writes every package from scratch, while this tool's install links to the file already in the store. For the user, the visible difference is usually just time and disk usage.

Running scripts, publishing packages, and pinning versions follow almost the same command syntax day to day, so there is very little new syntax for a team to learn.

What Points Commonly Get Confused About pnpm?

One myth is that this tool "compresses" packages or uses some different package format. In reality, it pulls from the same npm registry. What differs is how those packages get stored and linked on disk.

Another source of confusion is the idea that symlinks create a security risk. The default structure actually does the opposite: it makes it more obvious which package is truly declared, which cuts down on accidental dependency use.

Finally, some teams assume this tool only matters for large monorepos. Workspaces offer a strong advantage there, yet the disk saving and strict dependency checking apply just as much to a single small project.

Which Flags Do You Reach for Most on the Command Line?

The -w flag runs a command against the workspace root from inside a monorepo, no matter which package folder you are currently in. So you can add a root-level dependency without switching directories first.

The --filter flag targets a specific package or group of packages inside a workspace. In a large monorepo, running every command against the whole workspace wastes time, so filtering to the affected packages only saves real time.

You can bake these flags into your package.json scripts so team members never need to memorize the long command. A short script name does the same job.

Combining --filter with --recursive lets a command first select the target packages, then repeat the same action in each one. Once you set this pair up correctly, you can update every related package in a large monorepo with a single command, and the team avoids manual, error-prone steps.

Conclusion: Is pnpm the Right Choice for Your Project?

Coming back to what pnpm is: it is a package manager that saves disk space, resolves dependencies more strictly, and ships built-in monorepo support. Those three traits give many teams a strong reason to switch.

However, like any tool, it comes with trade-offs. If your older tools struggle with symlinks, or your team values consistency in one method, we recommend testing the switch on a small pilot project first.

If you are setting up a custom project environment and need support from choosing a package manager through to deployment, feel free to reach out to our team. Also, our ERESOLVE error guide, our gRPC guide, and our WSL2 guide can help while you set up a developer environment.

If you are curious about how package architecture plays out at the operating system level, take a look at our Linux package mirror guide. For anyone hitting package incompatibility on Apple Silicon, our Rosetta guide is worth a look too.

Frequently Asked Questions

Does pnpm replace npm?
Pnpm is a separate tool that pulls from the same npm registry, so you are not technically forced to remove npm. In your project, you run pnpm commands instead of npm commands, and node_modules gets built in a different structure. Avoiding mixing the two in one project prevents lockfile conflicts and keeps the whole team consistent.
Do I need to change my code after switching to pnpm?
Most projects need no code changes; what changes is how node_modules gets built. However, if your project secretly relies on a package it never declared in package.json, pnpm can block that phantom dependency, and you need to add the package explicitly. That fix is usually small and happens only once, though the team should know about it.
Is pnpm required for monorepo projects?
It is not required; monorepos can also run on npm or Yarn workspaces. However, pnpm's built-in support through pnpm-workspace.yaml, its shared lockfile, and the workspace: protocol manage internal package links more explicitly. That is why many teams prefer pnpm once they build a monorepo, and keep that habit over time.
Does pnpm work well on Windows?
Yes, pnpm works on Windows; it uses junctions instead of symlinks when Developer Mode is turned off. This difference stays invisible to the user, so installation and commands behave the same way either way. Still, we recommend checking your drive and file system compatibility before you start the setup.
What should I watch for when using pnpm in CI/CD?
Making sure the pnpm store gets cached in your CI/CD pipeline prevents packages from re-downloading on every build. Also, keeping the store and your project files on the same disk and file system preserves the hard-link advantage. If the drive differs, the tool has to copy files instead, and your saving shrinks.
Can I switch back from pnpm to npm?
Yes, you can; remove pnpm-lock.yaml and run npm install to let npm rebuild its own lockfile. Keeping both lockfiles around for a while before the switch makes the rollback safer if something goes wrong. If the team changes its mind, this step greatly lowers the risk either way.
  • pnpm
  • npm
  • yarn
  • node.js
  • package manager
  • monorepo
  • javascript
Share:
Talha Aslan

Google Partner digital marketing expert. Hands-on with SEO, Google Ads, web design and e-commerce projects since 2012; every post here comes from that experience.

Next project

Get a quote for your project.

Your brief goes straight to Talha Aslan and team: strategy led by Talha, delivery by an experienced team. We reply the same day and send the scope, timeline and price as a written quote within 1 business day.