DEV Community

Cover image for How to migrate from yarn / npm to pnpm
Andrei Chernykh
Andrei Chernykh

Posted on • Updated on

How to migrate from yarn / npm to pnpm

Motivation

pnpm is more performant at fetching, resolving, and storing dependencies. My personal experience shows that in some projects pnpm can be approx. 10x time faster at resolving dependencies and up to 3x more efficient for disk usage.

It is also easy to start using pnpm if you have used npm or yarn before because the CLI is very similar.

https://pnpm.io/motivation

Migration guide

Step 1: Install pnpm Installation
Step 2: Delete node_modules

npx npkill
Enter fullscreen mode Exit fullscreen mode

Step 3: Add to package.json

"scripts": {
  "preinstall": "npx only-allow pnpm", 
  ...
}
Enter fullscreen mode Exit fullscreen mode

This will prevent other devs from accidentally installing dependencies with anything else than pnpm

Step 4: Create pnpm-workspace.yaml

packages:
  # include packages in subfolders (e.g. apps/ and packages/)
  - "apps/**"
  - 'packages/**'
  # if required, exclude some directories
  - '!**/test/**'
Enter fullscreen mode Exit fullscreen mode

Step 4 (a): remove "workspaces" from "package.json", since it's no longer needed.

Step 5: Run

pnpm import
Enter fullscreen mode Exit fullscreen mode

This command will create a pnpm-lock.yaml file based on yarn.lock (or packages-lock.json)
Step 6: Remove yarn.lock (or packages-lock.json)
Step 7: Install dependencies

pnpm i
Enter fullscreen mode Exit fullscreen mode

Step 8: Replace npm run (or yarn) to pnpm in all package.json and other files (E.g. pnpm test instead of npm run test)

Important! You need to keep in mind that pnpm doesn’t use dependency hoisting:

When installing dependencies with npm or Yarn Classic, all packages are hoisted to the root of the modules directory. As a result, source code has access to dependencies that are not added as dependencies to the project.
By default, pnpm uses symlinks to add only the direct dependencies of the project into the root of the modules directory.
pnpm

In practice it means that if you have a package A that imports a package B (import something from 'B') but doesn’t explicitly specify B in the dependencies or devDependencies, then the execution will fail.

Cheatsheet

Tables Commands Cool
Install dependencies pnpm i https://pnpm.io/cli/install
Add a dependency pnpm add <package> https://pnpm.io/cli/add
Shows all packages that depend on the specified package pnpm why <package> https://pnpm.io/cli/why
Run a command as if it was executed form the root of the project rather than a workspace package pnpm -w <command> https://pnpm.io/pnpm-cli#-w---workspace-root
Restrict commands to specific subsets of packages pnpm --filter <package_selector> <command> https://pnpm.io/filtering
This runs an arbitrary command from each package's "scripts" object pnpm -r <command> https://pnpm.io/cli/run#--recursive--r

Top comments (20)

Collapse
 
equiman profile image
Camilo Martinez

I'm in a project transition moving from npm to pnpm and it is a nightmare to remember when using each one.

So I decided to create a command to do this. One command will translate to the respective PM.

npmjs.com/package/swpm

Collapse
 
andreychernykh profile image
Andrei Chernykh

Cool stuff!

Collapse
 
subbumsd profile image
Venkata Subbarao Myla

I found another package which does the same. github.com/antfu/ni

Collapse
 
equiman profile image
Camilo Martinez • Edited

I've tested ni and it is an amazing project too, but have a different approach.

ni focus only on commonly used commands and assign an alias to each one.

The SWPM key differences are:

  • Not limited to some commands or alias, you can use the whole Package Managers.
  • Flags to change his behavior on the fly, like say which Package Manager uses (for example when no lock file exists) or test the command translation.
  • Include a clean command to delete common folders like node_modules.
  • Also, have aliases (like ni) but include another set of commonly used alias like save-dev, exact-version, and others that have been requested by the users.
  • NVM and Volta compatible.
  • Detect lock files, but also work pining manually with the Package Managers (or with the use flag when even no lock file exists).
Collapse
 
imp87 profile image
Steven Dautrich

get all time: Invalid package manager specification in package.json; expected a semver version

in my package.json:

"name": "express-demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"preinstall": "npx only-allow pnpm",
"test": "echo \"Error: no test specified\" && exit 1"
},
"packageManager": "pnpm@7.1.7>",

Collapse
 
andreychernykh profile image
Andrei Chernykh

It looks like you have a redundant ">" there

"packageManager": "pnpm@7.1.7>",

should be

"packageManager": "pnpm@7.1.7",

Also, this line is optional. It is a node experimental feature. nodejs.org/api/corepack.html

I guess I better remove it from the example

Collapse
 
buzzdee profile image
Sebastian Schlatow

If I use npm ci in a Jenkins / GitLab pipeline, what command do I need to use with pnpm?

Collapse
 
andreychernykh profile image
Andrei Chernykh

I'm not 100% sure, but according to the docs (docs.npmjs.com/cli/v8/commands/npm-ci) one of the main features of npm ci is If dependencies in the package lock do not match those in package.json, npm ci will exit with an error, instead of updating the package lock.

pnpm docs says In a CI environment, installation fails if a lockfile is present but needs an update.
pnpm.io/cli/install

So, it looks like pnpm i behaves similar to npm ci. Try just pnpm i or pnpm install --frozen-lockfile

Here is a good answer on StackOverflow stackoverflow.com/questions/701545...

Collapse
 
james_palermo_bc208e463e4 profile image
James Palermo

Can pnmp be set up to allow fall back to npm, say if someone on a locked down/limited device (IoT or something) wants to pull a repo?

Collapse
 
andreychernykh profile image
Andrei Chernykh • Edited

I think it could. Just remove "preinstall": "npx only-allow pnpm",, so the person working with the repo could use npm to install dependencies.
And also, in that case it would make sense to keep packages-lock.json as well.

Note: these are my assumptions. I'm not a maintainer of pnpm and may not know some pitfalls.

Collapse
 
lico profile image
SeongKuk Han

Hoes does only-allow work? Does that detect when you run a script?

Collapse
 
arb99 profile image
Arberto99

Hi!
After following your tutorial to migrate an existing project from npm to pnpm (without any kind of problem) I run my app with "ng serve", as I was used to do with npm, and I get this errors:

`./src/main.ts - Error: Module build failed (from ./node_modules/.pnpm/@ngtools+webpack@14.2.10_7ypeylls7k.../node_modules/@ngtools/webpack/src/ivy/index.js):
Error: Emit attempted before Angular Webpack plugin initialization.

./src/polyfills.ts - Error: Module build failed (from ./node_modules/.pnpm/@ngtools+webpack@14.2.10_7ypeylls7k.../node_modules/@ngtools/webpack/src/ivy/index.js):
Error: Emit attempted before Angular Webpack plugin initialization.`

Any ideas about how to fix it?
Thanks a lot!

Collapse
 
revoltez profile image
revoltez

in my workspace i had the problem you described of importing packages, in npm it worked without modification, but now my package B which depends on package A can't find it, how do i add it in the dependecies?

Collapse
 
manoger profile image
Germano Brigido do Nascimento

For those having problems with moment and dotenv dependencies when migrating from npm to pnpm, simply add a .npmrc file with this content:

public-hoist-pattern[]=*eslint*
public-hoist-pattern[]=*prettier*
public-hoist-pattern[]=@types*
Enter fullscreen mode Exit fullscreen mode

issue reference

Collapse
 
ivomarsan profile image
Ivomar

The script preinstall is not working for me... I tried to use npm i and also runs

Collapse
 
jacksonkasi profile image
Jackson Kasi

hi! is pnpm support all npm packages?

Some comments may only be visible to logged-in visitors. Sign in to view all comments.