npm, Yarn, pnpm으로 보는 의존성 관리의 차이
패키지 매니저가 의존성을 설치하는 방식과 모노레포 구성 방법을 알아봐요
Table Of Contents
들어가기
외부 라이브러리를 설치하고 버전을 관리하는 도구가 패키지 매니저예요. 프로젝트가 동작하기 위해 필요한 외부 패키지를 의존성(dependency)이라고 하는데, JavaScript/TypeScript 생태계에서는 npm, yarn, pnpm이 이 의존성을 관리하는 대표적인 도구예요. 특히 여러 패키지를 한 저장소에서 관리하는 모노레포 환경에서는 이 차이가 더 크게 드러나요.
이 글에서는 npm, yarn, pnpm이 의존성을 어떻게 다르게 다루는지, 모노레포에서 어떤 차이가 생기는지를 다뤄요.
- 각 패키지 매니저의 설계 철학과 node_modules 구성 방식의 차이를 살펴보고,
- 모노레포에서 호이스팅, 격리, 내부 패키지 참조 방식이 어떻게 달라지는지 비교한 뒤,
- 디스크 효율, 설치 속도, 의존성 안전성을 기준으로 프로젝트에 맞는 선택 기준을 정리해요.
패키지 매니저의 이해
npm: node_modules로 의존성 설치하기
npm(Node Package Manager)은 Node.js와 함께 제공되는 기본 패키지 매니저예요.
npm install을 실행하면 package.json에 명시된 패키지와, 그 패키지가 의존하는 다른 패키지를 모두 node_modules 폴더에 설치해요.
npm v2까지는 의존성을 중첩 구조로 설치했어요.
패키지 A가 B를 필요로 하고, B가 C를 필요로 하면 node_modules/A/node_modules/B/...처럼 폴더가 깊어졌어요.
이 방식은 직관적이지만, 의존성 트리가 깊어지면 파일 경로가 수백 글자를 넘기도 해요.
Windows에서는 파일 경로가 260자를 넘으면 파일을 읽거나 삭제할 수 없는 문제가 있었어요.
node_modules/ ├── A/ │ └── node_modules/ │ └── B/ │ └── node_modules/ │ └── C/ ← 경로가 계속 깊어져요
npm v3부터는 이 문제를 해결하기 위해 의존성을 최상위 node_modules로 끌어올리는 호이스팅(hoisting)을 도입했어요.
중첩돼 있던 패키지가 최상위로 올라오면서 디렉터리 구조가 평탄화(flat)돼요.
node_modules/ ├── A/ ├── B/ └── C/ ← 모두 최상위에 설치돼요
경로가 깊어지는 문제는 해결됐지만, 모든 패키지가 최상위에 올라오면서 다른 문제가 생겼어요.
유령 의존성
유령 의존성(Phantom Dependency)은 package.json에 명시하지 않은 패키지를 코드에서 import할 수 있는 현상이에요.
예를 들어, package.json에 A만 명시했는데 A가 내부적으로 B를 사용해요.
평탄화 때문에 B도 최상위 node_modules에 올라와 있으므로, 내 코드에서 B를 직접 import해도 동작해요.
// package.json에는 A만 있어요 import something from "B"; // B는 A의 내부 의존성인데 평탄화 때문에 접근 가능해요
이 코드는 당장은 잘 동작하지만, A가 업데이트되면서 B를 더 이상 사용하지 않거나 버전을 바꾸면 해당 import가 실패하거나 예기치 않게 동작해요.
package.json에 없는 패키지에 의존하고 있으므로 원인을 찾기 어려운 버그가 돼요.
디스크 중복
디스크 중복은 같은 패키지가 프로젝트마다 각자 복사되어 디스크에 여러 벌 저장되는 문제예요.
한 프로젝트 안에서는 호이스팅 덕분에 react가 최상위에 한 벌만 있어요.
하지만 서로 다른 프로젝트가 10개 있고 각각 같은 react를 쓴다면, npm은 프로젝트마다 자기 node_modules를 따로 두고 그 안에 패키지 파일을 통째로 복사하므로, 디스크에는 같은 react가 10벌 저장돼요.
패키지 수가 수백 개인 프로젝트가 여러 개 있으면 node_modules만으로 수 GB를 차지하는 일도 드물지 않아요.
환경마다 다른 설치 결과
같은 package.json이라도 머신이나 설치 시점에 따라 받는 버전이 달라지는 문제가 있었어요.
package.json에 버전을 명시할 때는 보통 "lodash": "^4.17.0"처럼 시맨틱 버전 범위(semver range)를 써요.
^4.17.0은 "4.17.0 이상, 5.0.0 미만"이라는 뜻이에요.
npm은 설치 시점에 이 범위에 맞는 최신 버전을 골라서 내려받아요.
그래서 월요일에 설치하면 4.17.20이 들어오고, 수요일에 새 버전이 나온 뒤 설치하면 4.17.21이 들어올 수 있어요.
직접 명시한 패키지뿐 아니라, 그 패키지가 의존하는 하위 의존성도 같은 방식으로 범위가 풀려요.
의존성 트리가 깊어질수록 설치 시점에 따라 달라지는 버전이 많아져요.
개발자 A의 머신에서는 잘 동작하는데 개발자 B의 머신에서는 에러가 나는 문제가 빈번했어요.
설치 속도도 패키지를 하나씩 순차적으로 내려받는 방식이라 느렸어요.
이 문제는 yarn이 등장한 이후, npm에서도 lockfile을 도입하면서 해결되었어요. 자세한 내용은 yarn 섹션에서 살펴볼게요.
yarn: 설치 안정성과 속도 높이기
Yarn Classic
yarn은 2016년에 Facebook(현 Meta)이 만든 패키지 매니저예요. 앞에서 본 npm의 문제 중 설치 결과가 환경마다 달라지던 문제와 설치 속도를 해결하려고 나왔어요.
Yarn Classic(v1)은 이 문제들을 두 가지 방식으로 개선했어요.
yarn.lock파일로 모든 의존성의 정확한 버전을 고정했어요. lockfile에는 실제로 설치된 버전이 기록되므로, 다른 환경에서 설치해도 동일한 의존성 트리가 보장돼요.- 병렬 설치로 패키지를 동시에 내려받아서 설치 속도를 높였어요.
yarn이 lockfile을 도입한 뒤, npm도 v5(2017년)부터 package-lock.json을 도입했어요.
지금은 npm, yarn, pnpm 모두 lockfile을 지원하므로, 버전이 환경마다 달라지는 문제는 세 패키지 매니저 모두에서 해결된 상태예요.
Yarn Classic은 워크스페이스(workspaces)도 처음으로 도입해서, 하나의 저장소에서 여러 패키지를 관리하는 모노레포를 기본으로 지원했어요.
하지만 node_modules 구조는 npm v3+과 비슷한 평탄화 방식이라, 유령 의존성 문제는 여전했어요.
Yarn Berry PnP: zip 저장과 의존성 해결
Yarn Berry(v2 이상)는 완전히 새로운 접근을 해서 유령 의존성 문제를 해결해요.
Yarn Berry의 PnP(Plug'n'Play) 모드는 node_modules 폴더를 아예 만들지 않아요.
내려받은 패키지는 .yarn/cache/에 zip 파일 그대로 저장해요.
npm, Yarn Classic은 패키지를 압축 해제해서 node_modules에 수천~수만 개의 파일로 풀어놓지만, PnP는 zip을 풀지 않아요.
파일 수가 적어서 설치가 빠르고 디스크 사용량도 줄어요.
Node.js가 require("lodash")를 할 때 zip 안의 파일을 어떻게 찾냐면, .pnp.cjs가 "어떤 패키지가 어떤 zip의 어떤 경로에 있는지" 매핑해 두어요.
이 매핑에는 package.json에 선언한 의존성만 들어가요.
PnP가 모듈 탐색을 가로채서 그 매핑만 쓰므로, 선언하지 않은 패키지는 resolve 대상이 아니어서 import할 수 없어요. 유령 의존성이 차단되는 이유예요.
my-project/ ├── .pnp.cjs ← 패키지 이름 → zip 경로 매핑 ├── .yarn/cache/ ← 패키지가 zip으로 저장됨 │ ├── lodash-npm-4.17.21-xxxx.zip │ └── react-npm-18.3.1-xxxx.zip ├── package.json └── yarn.lock
zip 파일 끝에는 중앙 디렉터리(Central Directory)라는 목록이 있어서, 전체를 압축 해제하지 않아도 원하는 파일 위치를 찾아 읽을 수 있어요.
Yarn Berry는 require가 호출되면 이 구조를 이용해 zip 안의 해당 파일을 직접 읽어 반환해요.
PnP의 한계와 대안
Node.js 생태계의 많은 도구는 파일 시스템에 실제 경로가 있다고 가정해요.
webpack, ESLint, TypeScript 등은 fs.readFileSync, fs.existsSync로 파일을 읽는데, 파일이 zip 안에 있으면 이 방식이 통하지 않아요.
네이티브 바이너리(.node 파일)를 쓰는 패키지도 zip 안에서는 동작하지 않을 수 있어요.
Yarn Berry는 이런 경우 unplugged로 표시해서 zip에서 꺼내 실제 파일로 풀어 두는 예외 처리를 해요.
다만 어떤 패키지가 unplugged가 필요한지 찾고 설정하는 비용이 든다는 한계가 있어요.
호환성이 걱정되면 .yarnrc.yml에서 nodeLinker: node-modules로 두면 기존 node_modules 방식을 쓸 수 있어요.
pnpm은 이 호환성 문제를 다른 전략으로 우회하는데, 이어지는 섹션에서 살펴볼게요.
pnpm: 디스크 절약과 유령 의존성 차단하기
pnpm(performant npm)은 2017년에 등장한 패키지 매니저예요. npm과 yarn이 패키지를 프로젝트마다 복사하는 방식이라면, pnpm은 전역 저장소에 한 번만 저장하고 링크로 연결하는 방식이에요.
pnpm의 동작을 이해하려면 먼저 하드 링크와 심볼릭 링크를 알아야 해요.
파일 시스템에서 파일은 "이름"과 "실제 데이터"가 분리돼 있어요. 디스크에 저장된 실제 데이터 블록이 있고, 파일 이름은 그 데이터를 가리키는 포인터 역할을 해요.
하드 링크(hard link)는 같은 데이터 블록을 가리키는 이름을 하나 더 만드는 것이에요. 파일을 복사하면 데이터가 두 벌이 되지만, 하드 링크를 만들면 데이터는 한 벌 그대로고 이름만 두 개가 돼요. 어느 쪽 이름으로 열어도 같은 내용을 읽고, 디스크 공간도 추가로 들지 않아요.
심볼릭 링크(symlink, soft link)는 다른 파일의 경로를 가리키는 바로가기예요. 하드 링크가 데이터를 직접 가리킨다면, 심볼릭 링크는 "이 파일을 열려면 저쪽 경로를 봐라"라고 경로만 저장해요. 그래서 원본 파일이 삭제되면 따라갈 대상이 없어져 심볼릭 링크는 무효가 되지만, 하드 링크는 데이터를 직접 가리키므로 원본 이름을 지워도 그대로 유효해요.
pnpm의 콘텐츠 주소 저장소(Content-Addressable Store)는 전역 store 디렉터리에 모든 패키지 파일을 한 벌만 저장해요.
store 경로는 OS나 환경 설정(PNPM_HOME, XDG_DATA_HOME 등)에 따라 달라질 수 있어요.
패키지를 설치할 때 이미 저장소에 있는 버전이면 다시 내려받지 않고, 프로젝트의 node_modules에 하드 링크로 연결해요.
10개 프로젝트에서 react 18.3.1을 사용해도 디스크에는 한 벌만 존재하고, 각 프로젝트는 그 한 벌을 링크로 참조해요.
npm이라면 10벌을 복사해야 하는 것과 비교하면, 프로젝트가 많을수록 디스크 절약 효과가 커져요.
pnpm의 node_modules 구조도 npm, yarn과 다르게 동작해요.
node_modules/ ├── .pnpm/ │ ├── [email protected]/ │ │ └── node_modules/ │ │ └── react/ ← 전역 저장소의 하드 링크 │ └── [email protected]/ │ └── node_modules/ │ └── lodash/ ← 전역 저장소의 하드 링크 ├── react → .pnpm/[email protected]/node_modules/react ← symlink └── lodash → .pnpm/[email protected]/node_modules/lodash ← symlink
최상위 node_modules에는 package.json에 직접 명시한 패키지의 심볼릭 링크(symlink)만 있어요.
실제 파일은 .pnpm 폴더 안에 있고, 그 파일은 전역 저장소의 하드 링크예요.
이 구조 덕분에 pnpm은 유령 의존성을 원천 차단해요.
package.json에 명시하지 않은 패키지는 최상위 node_modules에 symlink가 없으므로, 코드에서 import하면 바로 에러가 나요.
npm이나 Yarn Classic에서는 평탄화 때문에 우연히 접근 가능했던 패키지가, pnpm에서는 명시적으로 추가하지 않으면 사용할 수 없어요.
모노레포에서 yarn과 pnpm 비교하기
앞에서는 패키지 매니저 각각의 설치 방식을 살펴봤어요. 이번에는 여러 패키지를 한 저장소에서 관리하는 모노레포 환경에서 yarn과 pnpm이 어떻게 다른지 비교해 볼게요.
모노레포(Monorepo)는 여러 패키지(앱, 라이브러리 등)를 하나의 Git 저장소에서 관리하는 방식이에요. 모노레포 안의 각 패키지를 워크스페이스(workspace)라고 불러요.
my-monorepo/ ├── package.json ← 루트 ├── packages/ │ ├── ui/ ← 워크스페이스 A │ │ └── package.json │ ├── utils/ ← 워크스페이스 B │ │ └── package.json │ └── web-app/ ← 워크스페이스 C │ └── package.json
모노레포에서는 워크스페이스끼리 서로 의존하기도 하고, 같은 외부 패키지를 공유하기도 해요. 패키지 매니저가 이 관계를 어떻게 관리하느냐에 따라 설치 속도, 디스크 사용량, 의존성 안전성이 달라져요.
의존성 호이스팅: 공유와 격리의 트레이드오프
호이스팅(hoisting)은 워크스페이스의 의존성을 루트 node_modules로 끌어올리는 방식이에요.
같은 패키지를 여러 워크스페이스에서 사용할 때 중복 설치를 줄이기 위한 전략이에요.
yarn과 pnpm은 호이스팅 전략이 다르고, 이 차이가 모노레포에서 가장 큰 차이를 만들어요.
yarn의 호이스팅 전략
Yarn Classic은 기본적으로 모든 의존성을 루트 node_modules로 호이스팅해요.
packages/ui와 packages/web-app이 같은 버전의 react를 사용하면, 루트 node_modules에 react를 한 번만 설치해요.
my-monorepo/ ├── node_modules/ │ ├── react/ ← 루트에 호이스팅됨 │ └── lodash/ ← 루트에 호이스팅됨 ├── packages/ │ ├── ui/ │ │ └── package.json ← react, lodash 의존 │ └── web-app/ │ └── package.json ← react만 의존
디스크 사용량은 줄지만, 앞에서 본 유령 의존성 문제가 모노레포에서는 더 심각해져요.
packages/web-app의 package.json에는 lodash가 없지만, packages/ui가 설치한 lodash가 루트에 호이스팅돼 있어 import가 되어버려요.
나중에 packages/ui에서 lodash를 제거하면 web-app에서 lodash import가 실패해서 빌드가 실패하거나 런타임 에러가 나요. 워크스페이스 간 보이지 않는 의존 관계가 생긴 것이에요.
Yarn Berry PnP 모드에서는 평탄화 방식의 호이스팅이 없으므로, package.json에 없는 패키지는 접근할 수 없어요.
Yarn의 node-modules 링크를 쓸 때는 nmHoistingLimits 같은 설정으로 호이스팅 범위를 조절할 수 있지만, 워크스페이스가 많아지면 설정이 복잡해질 수 있어요.
pnpm의 호이스팅 전략
pnpm은 기본적으로 호이스팅하지 않아요.
각 워크스페이스의 node_modules에는 자신의 package.json에 명시한 패키지의 symlink만 있어요.
my-monorepo/ ├── node_modules/ │ └── .pnpm/ ← 실제 파일은 여기에 하드 링크로 ├── packages/ │ ├── ui/ │ │ └── node_modules/ │ │ ├── react → ... ← package.json에 있으므로 symlink 존재 │ │ └── lodash → ... ← package.json에 있으므로 symlink 존재 │ └── web-app/ │ └── node_modules/ │ └── react → ... ← package.json에 있으므로 symlink 존재 │ ← lodash는 package.json에 없으므로 접근 불가
packages/web-app에서 lodash를 import하면 바로 에러가 나요.
워크스페이스 간 보이지 않는 의존 관계가 생길 수 없어요.
호환성 문제가 있다면 .npmrc에서 shamefully-hoist=true를 설정해서 npm처럼 평탄화할 수도 있어요.
하지만 이렇게 하면 pnpm의 엄격한 격리 장점을 포기하는 것이에요.
워크스페이스 선언과 내부 패키지 연결
호이스팅은 “설치된 파일이 어디에 놓이느냐”에 대한 이야기라면, 워크스페이스 설정은 “모노레포에서 어떤 폴더를 패키지로 볼 것이냐”와 “내부 패키지를 어떻게 연결할 것이냐”에 대한 규칙이에요.
워크스페이스 정의 파일
모노레포 안에서 어떤 폴더를 패키지(워크스페이스)로 볼지를 정해 줘야 해요.
예를 들어 루트 아래에 packages/ui, packages/utils, packages/web-app 세 개 폴더가 있고, 각각 package.json이 있다고 할게요.
이 세 폴더를 워크스페이스로 쓰려면 아래처럼 적어요.
yarn은 루트 package.json의 workspaces 필드에 글로브를 적어요.
packages/*는 "packages 아래의 모든 하위 폴더를 워크스페이스로 본다"는 뜻이에요.
{ "workspaces": ["packages/*"] }
pnpm은 전용 파일 pnpm-workspace.yaml에 같은 의미로 적어요.
packages: - "packages/*"
내부 워크스페이스 참조 방식
packages/web-app이 packages/ui와 packages/utils를 쓰는 경우처럼, 워크스페이스끼리 의존할 때는 package.json의 dependencies에 로컬 패키지 이름을 적어요.
yarn에서는 버전을 ^1.0.0처럼 적어도, 해당 이름이 워크스페이스에 있으면 yarn이 로컬 폴더와 연결해요.
Yarn Berry는 workspace: 프로토콜로 "로컬 워크스페이스에서만 가져온다"고 명시할 수 있어요.
{ "dependencies": { "@my-monorepo/ui": "workspace:*", "@my-monorepo/utils": "workspace:*" } }
pnpm도 workspace: 프로토콜을 쓰며, 로컬 워크스페이스 참조는 이 방식으로만 가능해요.
{ "dependencies": { "@my-monorepo/ui": "workspace:*", "@my-monorepo/utils": "workspace:*" } }
workspace:*는 "이 패키지는 반드시 로컬 워크스페이스에서 가져온다"는 뜻이에요.
실수로 npm 레지스트리에서 같은 이름의 패키지를 내려받는 사고를 방지할 수 있어요.
peer dependencies: 싱글턴 패키지 충돌 다루기
peer dependency는 "이 패키지를 쓰는 쪽(호스트)이 이 의존성을 직접 제공해야 한다"는 선언이에요.
React를 쓰는 라이브러리는 호스트 앱이 가진 React를 그대로 쓰려고 peerDependencies에 react를 넣는 경우가 많아요.
React처럼 런타임에 하나만 있어야 하는 싱글턴 패키지라서, 앱과 같은 인스턴스를 공유해야 하기 때문이에요.
모노레포에서 워크스페이스마다 다른 버전의 React가 설치되면, 빌드는 되지만 런타임에 "Invalid hook call" 같은 에러가 발생할 수 있어요. 두 개의 React 인스턴스가 섞이면서 훅 상태가 꼬이기 때문이에요.
peer dependencies를 처리하는 방법은 패키지 매니저마다 달라요.
-
npm(v7 이상)은 peer dependencies를 자동으로 설치해요. 충돌이 해결되지 않으면 설치가 실패할 수 있고, 경우에 따라 경고만 출력되기도 해요.
-
Yarn Classic은 peer dependencies를 자동 설치하지 않고 경고만 해요. 직접 추가해야 해요.
-
Yarn Berry는
packageExtensions로, 설치한 라이브러리가 peer dependency를 빠뜨렸더라도.yarnrc.yml에서 보완할 수 있어요. React처럼 한 인스턴스를 공유해야 하는 패키지에서 peer 선언 누락 때문에 중복 인스턴스가 생길 위험을 줄이는 데 도움이 돼요. -
pnpm은 peer dependencies가 설치돼 있는지, 요구 버전과 맞는지 검증해요. 기본값(
strict-peer-dependencies=false)에서는 누락되거나 버전이 안 맞으면 경고만 내고 설치는 진행해요..npmrc에strict-peer-dependencies=true를 두면 엄격 모드가 되어, peer가 없거나 버전이 맞지 않으면 설치가 실패해요. 그래서 런타임에 터지기 전에 설치 단계에서 문제를 막을 수 있어요.pnpm에서 엄격 모드를 쓰면 "빌드는 되는데 런타임에 에러가 나는" 문제를 더 이른 단계에서 잡는 데 도움이 돼요. 모노레포에서 싱글턴 패키지 버전을 통일하려면, 루트
package.json에 해당 패키지를 명시하고 워크스페이스에서는workspace:*로 참조하는 방식이 안전해요.
설치 성능과 디스크 사용량
모노레포에서는 워크스페이스가 많을수록 설치 속도와 디스크 사용량의 차이가 체감돼요.
설치 속도
pnpm은 전역 저장소에 이미 있는 패키지를 하드 링크로 연결하기만 하면 되므로, 캐시가 있는 상태에서의 재설치가 매우 빨라요. 네트워크 요청 없이 링크만 생성하면 되기 때문이에요.
Yarn Berry PnP는 node_modules 폴더를 만들지 않으므로 파일 I/O 자체가 적어요.
.yarn/cache에 zip 파일로 캐시하고, 설치 시 압축을 풀지 않아서 파일 생성 비용이 없어요.
Yarn Classic은 npm과 비슷한 수준이에요.
패키지를 node_modules에 복사하는 방식이라 파일 I/O가 많아요.
pnpm 공식 벤치마크에 따르면, lockfile과 캐시가 모두 있는 상태에서 pnpm은 npm 대비 약 2~3배 빠른 설치 속도를 보여줘요. 다만 프로젝트 크기, 네트워크 환경, 캐시 상태에 따라 수치는 달라질 수 있어요.
디스크 사용량
앞에서 본 디스크 절약 효과는 모노레포에서 더 커져요.
워크스페이스가 10개이고 각각 수백 개의 패키지를 사용한다면, npm이나 Yarn Classic은 워크스페이스마다 node_modules를 복사하므로 디스크 사용량이 워크스페이스 수에 비례해요.
pnpm은 전역 저장소의 한 벌을 모든 워크스페이스가 하드 링크로 공유하므로 증가폭이 작아요.
Yarn Berry PnP는 zip 압축 덕분에 디스크 사용량이 작지만, zero-install(캐시를 Git에 커밋하는 방식)을 사용하면 저장소 크기가 커질 수 있어요.
마치며
npm, yarn, pnpm은 같은 문제(의존성 관리)를 서로 다른 전략으로 풀어요.
정리하기
- npm은 Node.js 기본 패키지 매니저예요. 평탄화된
node_modules를 사용하고, 유령 의존성 문제가 있어요.- Yarn Classic은
yarn.lock과 병렬 설치로 안정성과 속도를 높였지만,node_modules구조는 npm과 비슷해요.- Yarn Berry PnP는
node_modules없이.pnp.cjs로 의존성을 관리해요. 디스크를 절약하고 유령 의존성을 차단하지만, 일부 도구와 호환성 문제가 있을 수 있어요.- pnpm은 전역 저장소와 하드 링크로 디스크를 절약하고, symlink 기반 구조로 유령 의존성을 차단해요.
- 모노레포에서 yarn은 호이스팅으로 의존성을 공유하고, pnpm은 격리를 기본으로 해요. 호이스팅은 디스크를 아끼지만 유령 의존성 위험이 있고, 격리는 안전하지만 의존성을 명시적으로 관리해야 해요.
패키지 매니저를 고를 때는 프로젝트 상황에 따라 기준이 달라져요.
- 기존 프로젝트와의 호환성이 중요하면 npm이나 Yarn Classic이 무난해요.
- 디스크 효율과 엄격한 의존성 관리가 필요하면 pnpm이 적합해요.
- zero-install이나 PnP를 통한 빠른 CI를 원하면 Yarn Berry를 고려할 수 있어요.
- 모노레포에서 유령 의존성을 확실히 차단하고 싶다면 pnpm이나 Yarn Berry PnP가 적합해요.
어떤 패키지 매니저가 "정답"이라기보다, 프로젝트 규모, 팀 구성원의 익숙함, 의존성 안전에 대한 요구 수준에 따라 적합한 선택이 달라져요.
Corepack으로 패키지 매니저 버전 통일하기
팀에서 패키지 매니저 버전을 통일하고 싶다면 Corepack을 쓸 수 있어요.
Corepack은 Node.js에 포함된 도구로, "이 프로젝트에서는 이 버전의 npm/yarn/pnpm을 쓴다"를 package.json 한 곳에 적어 두면, 그 버전을 자동으로 쓰게 해 줘요.
package.json에 packageManager 필드를 추가하면 돼요.
Corepack 포함 여부는 Node.js 버전에 따라 다를 수 있으니, 사용 중인 Node 문서를 확인하는 것이 좋아요.
{ "packageManager": "[email protected]" }
이렇게 설정하면 팀원이 다른 버전의 pnpm을 설치했더라도 프로젝트에서는 9.1.0을 사용하게 돼요. "내 컴퓨터에서는 설치가 되는데" 같은 문제를 줄일 수 있어요.
(출처: