pnpm은 콘텐츠 주소 기반 저장소로 디스크 사용량을 줄이고 의존성을 엄격하게 연결하는 패키지 매니저입니다. 설치와 기본 명령어뿐 아니라 packageManager, pnpm-lock.yaml, pnpm-workspace.yaml까지 함께 설정해야 팀과 CI에서 같은 결과를 재현하기 쉽습니다.- pnpm이란 무엇인가
- pnpm을 쓰는 이유
- pnpm 설치하기
- pnpm 기본 명령어
- 기존 npm 프로젝트에서 pnpm 사용하기
- 처음 도입할 때 체크리스트
- pnpm 워크스페이스 설정
- 공식 문서
pnpm이란 무엇인가

목표는 pnpm의 의존성 연결 방식을 이해하고 두 로컬 패키지를 workspace 프로토콜로 연결하는 것입니다. Node.js 스크립트와 package.json 기초가 필요합니다. 설치 도구 버전·lockfile·workspace 멤버 목록을 함께 확인해야 다른 컴퓨터에서도 같은 관계를 재현할 수 있습니다.
pnpm이라는 이름은 보통 Performant NPM으로 설명된다. 말 그대로 npm과 비슷한 사용 경험을 제공하면서 성능과 저장 공간 효율을 개선하는 데 초점을 둔 도구다. 그래서 처음 배울 때는 완전히 새로운 생태계를 익힌다고 생각하기보다, npm 명령어를 더 효율적인 방식으로 실행하는 도구라고 이해하면 쉽다.
npm, yarn, pnpm은 모두 같은 문제를 해결한다. 프로젝트가 의존하는 라이브러리를 내려받고, 버전을 기록하고, 다른 개발자나 배포 환경에서도 같은 의존성을 재현할 수 있게 돕는다. 차이는 의존성을 저장하고 연결하는 방식, 설치 속도, 잠금 파일 형식, 그리고 node_modules를 구성하는 방식에서 나타난다.
pnpm을 쓰는 이유
pnpm을 쓰는 가장 흔한 이유는 설치 속도와 디스크 공간이다. 여러 프로젝트를 동시에 다루다 보면 각 프로젝트마다 비슷한 패키지가 반복해서 설치된다. pnpm은 패키지를 전역 저장소에 한 번 저장해 두고, 각 프로젝트의 node_modules에는 필요한 참조를 연결하는 방식으로 중복을 줄인다.
이 구조 덕분에 같은 패키지를 여러 프로젝트에서 사용할 때 매번 새로 복사하는 부담이 줄어든다. 예를 들어 개인 프로젝트, 회사 프론트엔드 앱, 테스트용 Vite 프로젝트가 모두 react를 사용한다면, pnpm은 이미 저장된 패키지를 재활용할 수 있다. 결과적으로 설치 시간이 짧아지고 저장 공간도 아낄 수 있다.
또 하나의 장점은 의존성 관리가 비교적 엄격하다는 점이다. npm 환경에서는 직접 설치하지 않은 패키지가 우연히 node_modules 상위 구조에 있어서 코드에서 접근되는 경우가 생길 수 있다. pnpm은 프로젝트가 명시적으로 선언한 의존성 중심으로 접근을 제한하기 때문에, 숨은 의존성에 기대는 문제를 더 빨리 발견할 수 있다.
pnpm은 반복 설치되는 패키지의 중복을 줄인다.node_modules를 더 엄격하게 구성해 잘못된 의존성 사용을 드러내기 쉽다.package.json기반 흐름은 유지되므로npm사용자도 적응하기 쉽다.
pnpm 설치하기
기존 저장소에서는 package.json의 packageManager와 프로젝트 안내를 먼저 읽습니다. pnpm –version이 고정 버전과 일치해야 합니다. 이 글의 workspace 문법은 pnpm 10·11 계열에서도 사용하는 구성이고, 아래 실습 검증 도구는 pnpm 11.19.0입니다. 특정 숫자를 최신 버전이라는 의미로 복사하지 않습니다.
터미널에서 실행할 명령
node --version
pnpm --version2026-09-13 확인한 공식 설치 문서는 pnpm 12.x를 현재 릴리스 계열로 안내합니다. pnpm 12는 native 실행 파일이며 npm을 통한 설치에는 Node.js 22.13 이상이 필요합니다. 새 설치는 공식 설치 페이지의 운영체제별 절차를 확인하세요. pnpm 10/11 저장소를 학습하려고 도구만 12로 바꾸면 lockfile·설정 차이가 생길 수 있습니다.
Corepack을 쓰는 팀은 검증된 Corepack과 packageManager 버전으로 설치합니다. npm 전역 설치 방식과 Corepack shim을 동시에 덮어쓰지 마세요. Windows는 where.exe pnpm, bash는 command -v pnpm으로 실제 실행 파일 경로를 확인할 수 있습니다.
pnpm 기본 명령어

pnpm의 기본 명령어는 npm과 매우 비슷하다. 기존 프로젝트에서 의존성을 설치하려면 프로젝트 루트에서 pnpm install을 실행한다. 이 명령은 package.json과 pnpm-lock.yaml을 기준으로 필요한 패키지를 설치한다.
pnpm install
새 패키지를 추가할 때는 pnpm add를 사용한다. 예를 들어 런타임 의존성으로 axios를 추가하려면 아래처럼 실행한다. 이 경우 dependencies에 패키지가 기록된다.
pnpm add axios
개발할 때만 필요한 패키지는 -D 옵션을 붙인다. 예를 들어 typescript, eslint, vitest처럼 빌드나 검사, 테스트에 쓰는 도구는 보통 devDependencies에 둔다.
pnpm add -D typescript eslint vitest
패키지를 제거할 때는 pnpm remove를 사용한다. 이 명령은 node_modules에서 패키지를 제거하고 package.json의 의존성 목록도 함께 정리한다.
pnpm remove axios
package.json의 scripts에 등록된 명령을 실행할 때는 pnpm run을 사용한다. dev, build, test처럼 자주 쓰는 스크립트는 npm을 쓸 때와 거의 같은 감각으로 실행할 수 있다.
pnpm run dev
pnpm run build
pnpm run test
패키지를 업데이트할 때는 pnpm update를 사용한다. 전체 의존성을 업데이트할 수도 있고, 특정 패키지만 지정할 수도 있다. 다만 실무 프로젝트에서는 무작정 전체 업데이트를 하기보다 변경 범위를 확인하고 테스트를 함께 실행하는 편이 좋다.
pnpm update
pnpm update react
처음 익힐 때는 npm install은 pnpm install, npm install axios는 pnpm add axios, npm run dev는 pnpm run dev로 대응된다고 보면 된다. 명령 이름이 완전히 같지는 않지만, 의존성을 설치하고 스크립트를 실행한다는 작업 흐름은 거의 그대로 이어진다.
기존 npm 프로젝트에서 pnpm 사용하기
기존 npm 프로젝트에서도 대부분 package.json은 그대로 사용할 수 있다. pnpm은 dependencies, devDependencies, scripts 같은 기본 필드를 읽기 때문에, 패키지 목록과 스크립트 구조를 새로 작성할 필요는 없다. 보통은 프로젝트 루트에서 pnpm install을 실행하는 것부터 시작한다.
다만 잠금 파일은 달라진다. npm은 주로 package-lock.json을 사용하고, pnpm은 pnpm-lock.yaml을 사용한다. 팀에서 pnpm을 쓰기로 했다면 pnpm-lock.yaml을 저장소에 커밋하고 팀원 모두 같은 패키지 매니저를 사용해야 한다. 잠금 파일이 섞이면 설치 결과가 달라지거나 리뷰할 변경 사항이 불필요하게 늘어날 수 있다.
node_modules 구조 차이도 알아두면 좋다. pnpm은 패키지를 납작하게 모두 펼쳐 놓는 방식이 아니라, 전역 저장소와 심볼릭 링크를 활용해 필요한 패키지를 연결한다. 일반적인 앱 개발에서는 크게 의식하지 않아도 되지만, 일부 오래된 도구나 잘못 작성된 패키지는 직접 선언하지 않은 의존성을 암묵적으로 찾으려다가 문제가 생길 수 있다.
이런 문제가 발생하면 먼저 현재 코드나 설정이 실제로 사용하는 패키지를 package.json에 명시했는지 확인한다. 예를 들어 코드에서 lodash를 직접 가져오는데 lodash가 의존성에 없다면, 다른 패키지의 하위 의존성에 우연히 기대고 있던 것이다. 이때는 pnpm add lodash로 직접 의존성을 추가하는 편이 맞다.
- 기존
package.json은 대부분 그대로 사용할 수 있다. pnpm-lock.yaml은 팀과 공유해야 하는 중요한 파일이다.package-lock.json,yarn.lock,pnpm-lock.yaml을 동시에 운영하지 않는 것이 좋다.- 직접 사용하는 패키지는 반드시
dependencies나devDependencies에 명시한다.
처음 도입할 때 체크리스트
pnpm을 처음 도입할 때는 거창한 마이그레이션보다 작은 프로젝트에서 먼저 흐름을 익히는 편이 좋다. 새 Vite 프로젝트나 개인 Node.js 프로젝트에서 pnpm install, pnpm add, pnpm run dev를 반복해 보면 기존 npm과 어떤 부분이 같은지 금방 감이 온다.
pnpm create vite my-app
cd my-app
pnpm install
pnpm run dev
새 프로젝트 생성 흐름까지 확인하면 단순 설치 명령뿐 아니라 개발 서버 실행, 의존성 추가, 빌드까지 한 번에 점검할 수 있다.
팀 프로젝트에 적용한다면 패키지 매니저를 통일하는 것이 먼저다. 한 사람은 npm install을 실행하고 다른 사람은 pnpm install을 실행하면 잠금 파일과 설치 결과가 흔들릴 수 있다. 저장소에는 사용할 패키지 매니저와 버전을 문서화하고, 가능하면 packageManager 필드도 함께 둔다.
또한 CI 환경에서 설치 명령도 바꿔야 한다. 로컬에서는 pnpm을 쓰는데 배포 파이프라인에서는 여전히 npm ci를 실행하면 잠금 파일 기준이 맞지 않는다. CI에서는 보통 pnpm install --frozen-lockfile처럼 잠금 파일을 기준으로 재현 가능한 설치를 수행한다.
pnpm install --frozen-lockfile
pnpm run build
pnpm run test
- 새 프로젝트에서는 생성, 설치, 실행 명령을 한 번에 확인한다.
- 팀 프로젝트에서는 패키지 매니저와 잠금 파일을 하나로 통일한다.
CI에서는pnpm install --frozen-lockfile처럼 재현 가능한 설치 명령을 사용한다.- 오류가 나면 누락된 직접 의존성이 없는지 먼저 확인한다.
정리하면 pnpm은 npm을 대체하기 위해 모든 습관을 새로 배워야 하는 도구가 아니다. package.json 중심의 작업 방식은 유지하면서 설치 속도, 디스크 사용량, 의존성 명확성을 개선하고 싶을 때 시도하기 좋은 선택지다. 특히 여러 Node.js 프로젝트를 자주 만들거나 프론트엔드 앱의 설치 시간이 부담스럽다면, 다음 프로젝트부터 pnpm으로 시작해 보는 것이 가장 현실적인 입문 방법이다.
pnpm 워크스페이스 설정
빈 workspace-lab 폴더에 다음 여섯 파일을 만듭니다. 외부 패키지 없이 apps/web이 packages/message를 참조하므로 연결 원리를 네트워크 오류와 분리할 수 있습니다. packageManager는 실제 사용할 도구와 같은 정확한 버전으로 고정하며 아래는 검증한 11.19.0입니다.
package.json — 전체 파일
{
"name": "workspace-lab",
"private": true,
"packageManager": "pnpm@11.19.0"
}pnpm-workspace.yaml — 전체 파일
packages:
- "apps/*"
- "packages/*"packages/message/package.json — 전체 파일
{
"name": "@lab/message",
"version": "1.0.0",
"type": "module",
"exports": "./index.js"
}packages/message/index.js — 전체 파일
export const message = "workspace connected";apps/web/package.json — 전체 파일
{
"name": "@lab/web",
"private": true,
"type": "module",
"scripts": { "start": "node index.js" },
"dependencies": { "@lab/message": "workspace:^1.0.0" }
}apps/web/index.js — 전체 파일
import { message } from "@lab/message";
console.log(message);터미널에서 실행할 명령
pnpm install
pnpm --filter @lab/web start
pnpm -r list --depth -1
pnpm install --frozen-lockfilestart는 workspace connected를 출력해야 합니다. 재귀 목록에서는 @lab/web과 @lab/message 두 패키지를 확인합니다. workspace:는 로컬 workspace 패키지를 연결하려는 의도를 명시합니다. 이름이 틀리거나 멤버 목록에 없으면 실패할 수 있습니다. 버전 범위 검사는 도구 버전·설정에 따라 실제 동작을 확인하고 package 이름·API 호환성도 별도로 검토하세요.
root package.json, 각 패키지 package.json, pnpm-workspace.yaml, 생성된 pnpm-lock.yaml을 함께 관리하세요. 파일 변경이 의도와 맞을 때만 새 lockfile을 저장합니다. 삭제로 해결하려고 하기 전에 아래 오류 해결 글의 버전·멤버 진단을 먼저 적용합니다.
공식 문서
같이 읽으면 좋은 글
공식 근거와 실습 확인 범위
공식 문서 확인일: 2026-09-13. 작성·검수 기준: 1.0(2026-09-12). 아래 문서는 이 글에서 사용하는 명령·설정의 근거입니다.
pnpm 11.19.0에서 workspace install·start·frozen install을 실행했고, 없는 패키지 이름의 오류와 이름 복원 후 성공을 확인했습니다. 도구 설치·네트워크·Docker·GitHub Actions는 이 검증 환경에서 모두 실행했다고 주장하지 않습니다.
실습 파일 내려받기
Git·개발환경 실습 ZIP에 독립된 예제 폴더와 README를 제공합니다. 본문에 해당하는 폴더만 사용하고, 기존 프로젝트에 전체 압축을 덮어쓰지 마세요. Git은 같은 터미널에서 단계별 명령을 이어 실행하며 오류 재현 단계의 비정상 종료는 README의 예상 결과와 대조합니다.
이 글이 도움이 되었나요?
개발환경 학습 순서
필수 2개 · 전체 11개
읽음 기록 관리
전체 과정 목차 (11개)
- 필수 학습 · pnpm 사용법: 설치·기본 명령어·워크스페이스 설정 현재 글
- 선택 참고 · Yarn 사용법: Corepack 설치와 Classic·Modern 차이
- 필수 학습 · 환경변수 .env 파일 차이: local, example, development 기준
- 선택 참고 · npm install 의존성 충돌 해결: ERESOLVE 오류가 날 때 해결법
- 선택 참고 · pnpm install 오류 해결: lockfile·workspace 점검 순서
- 선택 참고 · Vite import.meta.env undefined 해결: VITE_ prefix 기준
- 선택 참고 · ESLint flat config 규칙 적용 안됨 해결: eslint.config.js 기준
- 선택 참고 · Tailwind CSS Unknown at rule 경고 해결: VS Code와 PostCSS 설정 확인
- 선택 참고 · Storybook Failed to fetch dynamically imported module 해결 (Vite)
- 선택 참고 · VS Code Copilot 디버깅: Agent Debug Log와 Chat Debug
- 시점·기록 · VS Code 1.113 업데이트: MCP와 Thinking Effort 변화
새 글 받아보기
RSS 리더에서 BlogFlow의 새 글을 확인할 수 있습니다.