npm과 pnpm은 둘 다 Node.js 패키지 매니저(Package Manager)다. 가장 큰 차이는 의존성을 디스크에 두는 방식이다. npm은 프로젝트마다 패키지를 복사해 평평한 node_modules를 만들고, pnpm은 전역 저장소에 한 번만 저장하고 프로젝트에는 링크만 건다.
npm: 평평한 node_modules
- 프로젝트가 10개면 같은 버전의 lodash가 10번 복사된다
- 의존성을 최상단으로 끌어올리는(Hoisting) 덕분에, package.json에 없는 패키지도 import하면 우연히 동작한다. 다른 패키지가 끌고 온 것을 몰래 쓰는 유령 의존성(Phantom Dependency)이다. 그 패키지가 버전을 바꾸거나 빠지면 갑자기 깨진다(하이럼의 법칙)
- 같은 라이브러리의 여러 버전이 중복 설치되면
npm dedupe로 줄인다. semver(Semantic Versioning)를 지킨다고 가정하고 호환되는 높은 버전 하나로 합친다(번들 크기 줄이기)
pnpm: 저장소 + 링크
- 패키지를 내용 기반 전역 저장소(content-addressable store)에 한 번만 저장하고, 각 프로젝트의
node_modules에는 하드 링크(Hard Link)와 심볼릭 링크(Symbolic Link)만 둔다 - 디스크 절약: 같은 버전은 컴퓨터 전체에서 한 벌이다
- 설치 속도: 이미 저장소에 있으면 내려받지 않고 링크만 건다
- 엄격함: 직접 선언한 의존성만 접근할 수 있게 구성해 유령 의존성을 구조적으로 막는다
| npm | pnpm | |
|---|---|---|
| 기본 제공 | Node.js에 포함 | 별도 설치 |
| 저장 방식 | 프로젝트마다 복사 | 전역 저장소 + 링크 |
| 유령 의존성 | 가능 | 차단 |
| 워크스페이스 | 지원 | 지원(엄격성 덕에 대규모에 유리) |
같은 package.json을 쓰고 명령도 거의 같아(npm install → pnpm install) 옮기기 쉽다. 평평한 구조를 가정한 일부 도구에서 드물게 문제가 난다. 여러 패키지를 한 저장소에서 다루는 구성은 pnpm 워크스페이스·모노레포·Turborepo·Nx 참고.