Yarn 15 ๐งถ Migrating from npm to Yarn
Migrating from npm to Yarn is not a single command. It is a sequence of decisions: which Yarn version to target, whether to use Plug’n’Play or node_modules, how to convert the lockfile, and how to reconfigure the settings that npm stored in .npmrc. The most common mistake is running yarn install on an npm project and assuming the migration is complete. The package-lock.json remains, the .npmrc settings are ignored by Yarn Berry, and the dependency tree may resolve differently than it did under npm.
Key point: Modern Yarn (2+) does not read .npmrc. Every registry, token, and configuration setting must be migrated to .yarnrc.yml. The lockfile conversion is handled by yarn import (for Yarn Classic) or by running yarn install after removing the npm lockfile (for Yarn Berry).
Why migration requires a deliberate sequence
The lockfile incompatibility problem. npm and Yarn use different lockfile formats. package-lock.json records the physical node_modules layout, including hoisting decisions. yarn.lock records only the logical dependency tree. Yarn Classic provides yarn import to generate a yarn.lock from an existing package-lock.json, minimizing the differences between the two resolutions . Yarn Berry, however, regenerates the lockfile during yarn install and does not use yarn import in the same way. The recommended path for Berry is to remove the npm lockfile and let Yarn resolve from package.json.
The .npmrc problem. Yarn Classic read .npmrc for registry configuration. Yarn Berry ignores it entirely. Settings like registry, //registry.npmjs.org/:_authToken, and always-auth must be translated into .yarnrc.yml syntax: npmRegistryServer, npmAuthToken, and npmAlwaysAuth . A project that migrates without this step will fail to install private packages.
The pre/post script problem. Yarn Classic and npm automatically ran prestart before start and poststart after. Yarn Berry removed this implicit behavior. A script named prestart is no longer called automatically; it must be invoked explicitly: "start": "yarn prestart && http-server" . This is a breaking change that affects any project relying on lifecycle script magic.
The yarn global problem. Yarn Berry removed the yarn global command entirely. System-wide package installation is outside Yarn’s scope. The replacement for one-off global tools is yarn dlx, which installs the package temporarily and runs it without polluting the global environment .
The bundleDependencies problem. This npm feature embeds dependencies inside the package archive. It assumes a node_modules layout, which does not exist under Plug’n’Play. Yarn Berry recommends removing bundleDependencies and using a bundler (Esbuild, Webpack, Rollup) for standalone distributions .
a. Migrating to Yarn Classic (1.x)
Yarn Classic is the simplest migration path. It is compatible with the npm package.json format, reads .npmrc, and can import the npm lockfile directly.
# Install Yarn Classic globally (if not already installed)
npm install -g yarn
# Import the existing package-lock.json
yarn import
# Run the install
yarn install
The yarn import command reads package-lock.json and generates a yarn.lock with the same resolution. If no package-lock.json exists, it falls back to reading node_modules using standard require.resolve() rules . Warnings are printed when Yarn cannot express the npm tree identicallyโfor example, when npm resolved two different versions of the same semver range, which yarn.lock cannot represent .
After yarn import succeeds, delete package-lock.json to prevent confusion. Yarn Classic still reads .npmrc for registry settings, so no .yarnrc migration is required at this stage.
b. Migrating to Yarn Berry (2+)
Yarn Berry is the modern version (2, 3, 4). It uses .yarnrc.yml, supports Plug’n’Play, and requires Corepack for version management.
# Enable Corepack (once per machine)
corepack enable
# Set the Yarn version to Berry
yarn set version berry
# Remove the npm lockfile
rm package-lock.json
# Run the install
yarn install
The yarn set version berry command downloads the latest Berry release and configures the project to use it . The package-lock.json is removed because Berry generates its own yarn.lock during install. The resulting dependency tree may differ from npm’s, particularly in hoisting decisions.
By default, Yarn Berry uses Plug’n’Play. If the project’s tools are incompatible with PnP, fall back to node_modules:
# .yarnrc.yml
nodeLinker: node-modules
This preserves the traditional layout while still using Berry’s resolution and caching mechanisms .
c. Migrating .npmrc to .yarnrc.yml
Every .npmrc setting that affects registry access must be translated. The syntax changes from INI to YAML, and the keys are renamed.
# .yarnrc.yml
npmRegistryServer: "https://registry.npmjs.org"
npmAuthToken: "${NPM_TOKEN}"
npmAlwaysAuth: true
For scoped registries, use npmScopes:
npmScopes:
my-company:
npmRegistryServer: "https://npm.internal.example.com"
npmAuthToken: "${INTERNAL_NPM_TOKEN}"
The .npmrc file can be deleted after migration. Yarn Berry does not read it, and leaving it in place creates confusion about which configuration is authoritative .
Complete Example Session
# ============================================
# PART 1: VERIFY NODE VERSION
# ============================================
node --version
# v20.11.0 or later required for Yarn Berry
# ============================================
# PART 2: ENABLE COREPACK
# ============================================
corepack enable
# Corepack is now the router for yarn commands
# ============================================
# PART 3: SET YARN VERSION TO BERRY
# ============================================
yarn set version berry
# Downloads Yarn 4.x and configures .yarnrc.yml
# ============================================
# PART 4: REMOVE NPM LOCKFILE
# ============================================
rm package-lock.json
# Berry generates its own lockfile
# ============================================
# PART 5: MIGRATE .NPMRC TO .YARNRC.YML
# ============================================
# Delete .npmrc after translating its settings
cat > .yarnrc.yml <<'EOF'
npmRegistryServer: "https://registry.npmjs.org"
npmAuthToken: "${NPM_TOKEN}"
EOF
# ============================================
# PART 6: CHOOSE LINKER
# ============================================
# For PnP (default in Berry):
# (nothing to add)
# For node_modules compatibility:
echo "nodeLinker: node-modules" >> .yarnrc.yml
# ============================================
# PART 7: RUN INSTALL
# ============================================
yarn install
# Generates yarn.lock and .pnp.cjs (or node_modules)
# ============================================
# PART 8: UPDATE SCRIPTS FOR BERRY
# ============================================
# Rewrite pre/post scripts to be explicit
# "start": "yarn prestart && http-server"
# ============================================
# PART 9: COMMIT CHANGES
# ============================================
git add .yarnrc.yml yarn.lock .pnp.cjs .pnp.loader.mjs
git commit -m "Migrate from npm to Yarn Berry"
The nine parts trace the Berry migration: verifying Node, enabling Corepack, setting the version, removing the npm lockfile, translating .npmrc, choosing the linker, installing, updating scripts, and committing.
Quick Reference
Command Translation
| npm | Yarn Classic | Yarn Berry |
|---|---|---|
npm install | yarn | yarn install |
npm ci | yarn install --frozen-lockfile | yarn install --immutable |
npm install <pkg> | yarn add <pkg> | yarn add <pkg> |
npm install -D <pkg> | yarn add -D <pkg> | yarn add -D <pkg> |
npm run <script> | yarn run <script> | yarn <script> |
npm uninstall <pkg> | yarn remove <pkg> | yarn remove <pkg> |
npm install -g <pkg> | yarn global add <pkg> | yarn dlx <pkg> |
File Migration
| npm File | Yarn Berry File | Action |
|---|---|---|
package-lock.json | yarn.lock | Remove npm lockfile; Yarn generates new |
.npmrc | .yarnrc.yml | Translate registry settings |
node_modules/ | .yarn/cache/ or node_modules/ | Depends on nodeLinker |
Configuration Translation
.npmrc | .yarnrc.yml |
|---|---|
registry=https://... | npmRegistryServer: "https://..." |
//registry/:_authToken=xxx | npmAuthToken: "xxx" |
always-auth=true | npmAlwaysAuth: true |
Best Practices
โ Do This:
yarn set version berry
<!-- Use Berry for new migrations --> # โ
nodeLinker: node-modules
<!-- Fall back if PnP breaks tools --> # โ
# Rewrite pre/post scripts explicitly
- โ Berry does not run them automatically
โ Don’t Do This:
# Keep .npmrc after migrating to Berry
- โ Berry ignores it; configuration is invisible
# Assume yarn import works in Berry
- โ
yarn importis a Classic feature; Berry regenerates
# Use yarn global in Berry
- โ Removed; use
yarn dlx
Common Pitfalls
| Pitfall | Why It Happens | Fix |
|---|---|---|
| Private packages fail | .npmrc not migrated | Translate to .yarnrc.yml |
prestart not running | Berry removed implicit lifecycle | Call explicitly in start script |
| PnP breaks a tool | Tool assumes node_modules | Set nodeLinker: node-modules |
| Lockfile conflicts | Both package-lock.json and yarn.lock present | Delete npm lockfile |
yarn global not found | Removed in Berry | Use yarn dlx |
Real-World Examples
1. Classic Import
yarn import
2. Set Berry
yarn set version berry
3. Remove npm Lockfile
rm package-lock.json
4. Fallback to node_modules
nodeLinker: node-modules
5. Translate Registry
npmRegistryServer: "https://registry.npmjs.org"
6. Translate Token
npmAuthToken: "${NPM_TOKEN}"
7. Scope Configuration
npmScopes:
my-company:
npmRegistryServer: "https://npm.internal"
8. Explicit Script Call
"start": "yarn prestart && http-server"
9. One-Off Tool
yarn dlx create-react-app
10. Immutable Install
yarn install --immutable
Visual
Migration Decision Path
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Which Yarn version? โ
โโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโ
โ CLASSIC (1.x) โ BERRY (2+)
โผ โผ
โโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโ
โ yarn import โ โ yarn set version โ
โ (uses npm lockfile) โ โ berry โ
โ โ โ rm package-lock.jsonโ
โ Reads .npmrc โ โ Translate .npmrc โ โ
โ โ โ .yarnrc.yml โ
โโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโ
Classic is a drop-in replacement. Berry requires configuration migration.
Configuration Migration
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ .npmrc (ignored by Berry) โ
โ registry=https://registry.npmjs.org โ
โ //registry/:_authToken=xxx โ
โโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ .yarnrc.yml โ
โ npmRegistryServer: "https://..." โ
โ npmAuthToken: "${NPM_TOKEN}" โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
The syntax changes; the intent is preserved.
Summary
| Item | Value |
|---|---|
| Classic import | yarn import (uses package-lock.json) |
| Berry migration | yarn set version berry + remove npm lockfile |
.npmrc | Ignored by Berry; translate to .yarnrc.yml |
| Registry key | npmRegistryServer |
| Token key | npmAuthToken |
| PnP fallback | nodeLinker: node-modules |
pre/post scripts | Must be called explicitly |
yarn global | Removed; use yarn dlx |
Key takeaways:
- Yarn Classic migrates smoothly; Berry requires configuration work.
yarn importhandles the lockfile for Classic. Berry ignores.npmrcand regenerates the lockfile. .npmrcis dead in Berry. Every registry and authentication setting must be translated to.yarnrc.ymlwith the new key names .- PnP is the default in Berry, but not mandatory. Setting
nodeLinker: node-modulespreserves compatibility with tools that assume a filesystem layout. - Lifecycle scripts are explicit.
prestartandpoststartare no longer implicit. Thestartscript must call them directly. yarn globalis gone. One-off tools are executed withyarn dlx, which installs temporarily and discards the package.
Remember: Migration is not a command. It is a sequence of decisions. Choose the Yarn version. Choose the linker. Translate the configuration. Remove the conflicting lockfile. Then install. The dependency tree may change, and that is expectedโYarn’s resolution algorithm is not identical to npm’s. Test the application after migration, and commit the new lockfile alongside the configuration.
Stop using slow, ad-bloated tool sites! ๐คฎ
๐ Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
โ
Finance (Mortgage, Interest, Inflation)
โ
Tech (Base64, JSON, Dev Suite, IP)
โ
Health (BMI, BMR, TDEE)
โ
Productivity (Timer, Workspace, QR)
โก๏ธ Fast & Private
๐ No data leaves your device
๐ 100% Free
๐ Use it now: https://tools.kandz.me
๐ Bookmark itโyouโll need it later!