Vælg din package manager før den vælger dig
Det korte svar er at du skal vælge én package manager, skrive den ned og holde dig stædigt til den. Men det længere svar er mere interessant.
Jeg landede selv i et projekt hvor nogle brugte npm, andre sværgede til yarn, og én havde læst på Twitter at pnpm var fremtiden. Resultatet var tre forskellige lockfiles, en node_modules-mappe på størrelse med min søns Minecraft-world og en CI der fejlede tilfældigt. Det var her jeg besluttede at få styr på, hvad forskellen egentlig er, og hvordan man vælger uden at fortryde om tre måneder.
Hvad der faktisk ændrer sig mellem npm, yarn og pnpm
Jeg starter altid med det samme lille eksperiment, når jeg tester værktøjer: opret et nyt projekt, installer et par pakker og se hvad der sker på disken.
mkdir test-pm
cd test-pm
npm init -y # eller yarn init -y / pnpm init -y
npm install react react-dom # tilsvarende for yarn/pnpm
Hvis du kører det med hver af de tre, får du tre ret forskellige verdener.
npm: standarden, som alle kender
Fordele:
- Følger med Node, alle forstår det
- Lockfile:
package-lock.jsoner standard i rigtig mange projekter - Nyere npm-versioner har fornuftig performance og caching
Ulemper:
node_moduleskan blive meget stor- NPM har haft lidt svingende adfærd mellem store versionshop
I praksis er npm fint til alt fra små hobbyprojekter til mellemstore apps. Det er også det tryggeste valg hvis du ikke gider forklare kolleger noget som helst.
Yarn: hurtigt barn af frustration over npm
Yarn kom som svar på gamle npm-problemer: langsomme installs og uforudsigelige dependency-træer.
Fordele:
- Lockfile:
yarn.locker stabil og nem at committe - God performance, især i v1 (Classic)
- Brugt af mange store open source projekter
Ulemper:
- Der er forskel på Yarn v1 (Classic) og Yarn Berry (v2+)
- Zero-install og PnP kan forvirre, hvis teamet ikke er med
Når du ser en yarn.lock i repoet, er det typisk fordi nogen på holdet tidligere har haft ondt i npm. Yarn er stadig solidt, men nyere npm har indhentet meget af forskellen.
pnpm: disk-sparer med strengere regler
pnpm ændrer én ting radikalt: hvordan node_modules er bygget.
- Lockfile:
pnpm-lock.yaml - Global content-adresseret cache (pakker gemmes én gang, linkes ud)
- Strammere
node_modules-struktur, så utilsigtet dependency hoisting afsløres
Det gør to ting:
- Diskforbruget falder markant, især på monorepos
- Skjulte dependency-fejl kommer frem, fordi pnpm ikke automatisk “hjælper” dig med for brede imports
Hvis du vil have en hurtig fornemmelse, så kig på pnpm’s egen forklaring. De viser meget visuelt, hvad der sker med links og cache.
Beslutningsmatrix – svar på fem spørgsmål og vælg
Jeg begyndte først at få ro i maven, da jeg skrev mit valg ned som en lille tjekliste. Den ser sådan her ud i dag.
1. Er I et team, eller sidder du alene?
- Solo-projekt: vælg det du selv forstår bedst. Typisk npm eller pnpm.
- Team: vælg det flest allerede kender, med mindre der er tung vægt imod.
Hvis halvdelen af teamet allerede har brugt pnpm og resten er grøntsager på package manager-fronten, så vælg pnpm. Omvendt: hvis alle tænker npm install helt automatisk, så lad være med at kæmpe imod bare for sport.
2. Har du (eller får du) et monorepo?
Monorepo: flere pakker / apps i samme repository. Fx apps/web, apps/api, packages/ui.
- Ingen monorepo-planer: npm er fint, Yarn er fint, pnpm er fint.
- Monorepo nu eller senere: pnpm eller Yarn Workspaces vinder typisk.
Pnpm har en naturlig monorepo-historie. Yarn Workspaces er også stærkt. Npm har workspaces nu, men tooling og vaner halter lidt efter.
3. Hvor følsom er du over for disk og install-tid?
- Mange projekter på samme maskine: pnpm sparer dig for mange GB.
- Lille setup, få projekter: forskellen er til at leve med, vælg efter simpelt workflow.
På min egen laptop kunne jeg se forskel, da jeg gik fra blandet npm/yarn til primært pnpm. Færre kaffepauser mens node_modules pakkes ud.
4. Hvad bruger jeres CI/CD lige nu?
- CI kører npm: behold npm, med mindre du får lov at rydde op i pipelines.
- CI er allerede sat op til Yarn: behold Yarn, med mindre du har en god migreringsplan.
- Ny pipeline: så er pnpm et stærkt bud, især med cache.
At skifte package manager uden at kigge på CI er den sikre vej til “det virker lokalt”-helvede. Det er også her mange lockfile-fejl starter.
5. Har du constraints udefra? (hosting, skabeloner, frameworks)
- Nogle frameworks forventer npm (f.eks. simple
create-*-skabeloner) - Andre har pnpm eller Yarn som anbefalet default
Jeg plejer at holde mig til frameworkets recommendation, med mindre jeg har en meget konkret grund til noget andet. Det gør debugging nemmere, når du googler fejl og ser samme værktøj i eksemplerne.
Opsummeret valg
Hvis jeg starter i dag, og jeg må vælge frit:
- Lille hobbyapp alene: npm (mindst friktion, standardværktøj)
- Større projekt eller monorepo: pnpm
- Eksisterende team med Yarn: behold Yarn, ryd op og standardiser
Og så skriver jeg det ned i README som en regel, ikke som en løs idé.
Lockfiles – hvad de låser, og hvorfor de skaber støj
Lockfiles er årsagen til en stor del af forvirringen, men også grunden til at dine builds ikke eksploderer hver tirsdag.
Hvad låser de?
Når du har en package.json med fx:
{
"dependencies": {
"react": "^18.2.0"
}
}
så siger du: “giv mig en eller anden version af React der er kompatibel med 18.2.0″. Det er et interval.
Lockfilen siger: “brug præcis denne version, hentet fra præcis denne URL, med denne checksum”.
package-lock.jsontil npmyarn.locktil Yarnpnpm-lock.yamltil pnpm
Det gør at:
- Din kollega får samme dependency-træ som dig
- CI kan reproducere builds
Hvorfor de giver merge-konflikter
Forestil dig to grene:
- Gren A: du tilføjer
axios - Gren B: din kollega tilføjer
zustand
Begge kører npm install (eller Yarn/pnpm) og committer lockfilen. Nu har I to forskellige lockfiles. Når de merges, vil Git ofte vise konflikter.
Det er irriterende, men ikke farligt. Den typiske løsning er:
- Behold én sides lockfile ved merge (eller løs konflikten mekanisk)
- Kør
npm install(eller tilsvarende) igen - Commit den opdaterede lockfile
Fejlen er ikke at lockfile ændrer sig. Fejlen er at nogen forsøger at redigere den i hånden. Lad værktøjet gøre arbejdet.
Typisk fejl: flere lockfiles i samme repo
Hvis du har både package-lock.json og yarn.lock i roden, er du allerede i problemer.
- Npm ignorerer
yarn.lock, Yarn ignorererpackage-lock.json - CI kan bruge én af dem, din laptop bruger en anden
- Du ender med “works on my machine” hver gang en dependency opdateres
Derfor: én package manager, én type lockfile. Slet resten.
Corepack – skriv din package manager ind i projektet
Node har fået et værktøj, som hjælper med at standardisere: Corepack.
Corepack gør to ting:
- Installerer og wrapper npm, Yarn og pnpm
- Læser
packageManager-feltet ipackage.json
Sådan slår du Corepack til
# globalt på din maskine
corepack enable
Nu kan Corepack sørge for de rette versioner. Du fortæller projektet hvad du vil bruge:
{
"name": "mit-projekt",
"packageManager": "pnpm@9.1.0"
}
Når en ny udvikler kloner projektet og kører pnpm install, vil Corepack hente og bruge den rigtige pnpm-version.
Fordel i teams og CI
Det giver tre konkrete gevinster:
- Mindst én kilde til sandhed for package manager-version
- CI og udviklermaskiner kan matche uden ekstra opsætning
- Mindre “hos mig er det npm 8, hos dig er det npm 10”-forvirring
Hvis du allerede arbejder med fx Node 18 eller 20, giver det mening at gøre Corepack til en del af din standard setup, fx beskrevet i din README sammen med andre ting som migrations-strategi.
Typiske fejl og hurtige fixes
Her er de fejl jeg selv støder på oftest, når package manageren ikke er aftalt, eller når nogen lige “tester” et andet værktøj lokalt.
1. “Cannot find module” efter skift
Symptom: Lokalt virker det, CI fejler, eller omvendt.
Årsag: node_modules er bygget med én package manager, men du installerer eller kører scripts med en anden.
Løsning:
rm -rf node_modules
rm package-lock.json yarn.lock pnpm-lock.yaml # behold kun den rigtige type
npm install # eller yarn install / pnpm install
Commit ny lockfile, og skriv i README hvilken package manager der er valgt.
2. Peer dependency warnings bliver til runtime-fejl
Symptom: Du får lange advarsler om peer dependencies, især når du bruger React, bundlere eller UI-biblioteker.
Årsag: Pakker forventer bestemte versioner af andre pakker. Forskellige package managers håndterer det en smule forskelligt.
Løsning: Installer de manglende dependencies eksplicit.
# eksempel
pnpm add react@18 react-dom@18 --save
Kig i warnings, og ryd systematisk op. Pnpm er god til at afsløre de steder, hvor du har været lidt løs i kanterne.
3. Checksum mismatch i CI
Symptom: CI fejler med noget ala “checksum mismatch” eller “integrity check failed”.
Typiske årsager:
- Korrupt cache i CI
- Lockfile committet, men ændret manuelt
- Forskellig package manager-version mellem lokal og CI
Løsning:
- Ryd cache i CI (fx slet
~/.npm, pnpm store eller lignende mappen i CI-konfigurationen) - Sørg for at CI bruger samme package manager-version, evt. via Corepack
- Kør en frisk install lokalt og commit opdateret lockfile
4. CI bruger npm, repoet bruger pnpm
Symptom: Lokalt kører du pnpm install, men i CI står der npm ci i workflow-filen.
Mønster: Projektet er startet med npm, senere er nogen skiftet til pnpm uden at ændre CI.
Løsning: Gør det samme i CI som du gør lokalt.
# eksempel med GitHub Actions
- name: Install dependencies
run: pnpm install --frozen-lockfile
Og slet evt. package-lock.json, så der ikke er tvivl.
Migration uden at vælte alt: npm ↔ pnpm ↔ yarn
Jeg har efterhånden migreret et par projekter, både alene og i små teams. Grundreglen er: gør det så kedeligt som muligt.
Fra npm til pnpm
- Installer pnpm (gerne via Corepack)
corepack enable
corepack prepare pnpm@latest --activate
- Slet gamle artefakter
rm -rf node_modules package-lock.json
- Installer med pnpm
pnpm install
- Opdater scripts i
package.json
{
"scripts": {
"dev": "pnpm run start", // eller hvad du bruger
"build": "pnpm run build"
},
"packageManager": "pnpm@9.1.0"
}
Ofte kan du beholde scripts som "dev": "next dev", det er kun i dokumentation og README at du skriver pnpm i stedet for npm.
Fra Yarn til pnpm
Samme idé, bare med yarn.lock i stedet.
rm -rf node_modules yarn.lock
pnpm install
Opdater README, CI workflows og evt. skabeloner til at bruge pnpm. Tjek at monorepo-opsætning (workspaces) matcher pnpm’s forventninger.
Fra pnpm tilbage til npm
Nogle gange er det omvendt: du sidder i et projekt hvor pnpm skaber forvirring, fordi resten af organisationen kun kender npm.
rm -rf node_modules pnpm-lock.yaml
npm install
Npm vil generere en package-lock.json, som du committer. Husk at fjerne packageManager-feltet eller sætte det til npm i package.json:
{
"packageManager": "npm@10.8.0"
}
Og så igen: opdater CI og dokumentation.
Mine standardvalg til et nyt projekt
Når jeg starter et nyt Node/JS-projekt i dag, gør jeg typisk noget i den her stil.
1. Init med npm, vælg package manager bagefter
mkdir ny-app
cd ny-app
npm init -y
Herfra beslutter jeg mig:
- Hvis det er lille solo-projekt: jeg bliver på npm
- Hvis det kan vokse, eller jeg vil genbruge kode: jeg skifter til pnpm med det samme
2. Sæt engines og packageManager
I package.json skriver jeg noget a la:
{
"engines": {
"node": ">=20.0.0"
},
"packageManager": "pnpm@9.1.0"
}
På den måde får nye udviklere en fejl, hvis de bruger meget gammel Node, og Corepack kan hente den rigtige version af pnpm.
3. Scripts der ikke låser sig til én CLI
Jeg prøver at holde scripts neutrale:
{
"scripts": {
"dev": "next dev",
"build": "next build",
"lint": "eslint ."
}
}
Så kører jeg dem med valgt package manager:
pnpm dev
# eller
npm run dev
Hvis jeg en dag skulle skifte værktøj, er der mindre at rette.
Det samme princip bruger jeg på andre områder, fx feature flags, som jeg skrev om i artiklen om at shippe mindre ad gangen. Jo færre hårde afhængigheder i kernen, jo nemmere at skifte uden drama.
Hvornår du ikke skal skifte package manager
Alt det her kan hurtigt lyde som en opfordring til at skifte alt til pnpm i morgen. Det synes jeg faktisk ikke.
Behold det der ikke skaber problemer
Hvis du har et projekt der:
- Bruger npm
- Har én lockfile
- Kører stabilt i CI
- Ikke sluger hele disken
så vil jeg oftest lade det være. Din energi er bedre brugt på at få styr på tests, logging eller f.eks. mere stabil JavaScript-CI.
Skift først, når du har ét tydeligt problem
Jeg skifter kun package manager i eksisterende projekter hvis mindst én af de her er sand:
- Diskforbrug og install-tid er reelt et problem
- Monorepo-struktur er bøvlet med nuværende værktøj
- Teamet er allerede forvirret over blandede værktøjer og lockfiles
Og så laver jeg det som en dedikeret ændring, ikke som en sideeffekt af “jeg skulle lige opdatere en dependency”.
Det handler i virkeligheden om det samme som med database-migrationer og andre “usynlige” systemvalg: jo mere bevidst du tager beslutningen, jo mindre tid spilder du senere på mærkelige fejl, som ingen helt kan forklare.
Om et par år tror jeg vi vil se tilbage på de her værktøjsvalg lidt som valg af brætspil: reglerne er forskellige, men det vigtigste er at alle ved hvilket spil I spiller, og at ingen pludselig begynder at spille noget andet midt i runden.









Send kommentar
Du skal være logget ind for at skrive en kommentar.