package.json
패키지의 매니페스트 파일입니다. 여기에는 의존성, 제목, 작성자 등을 포함한 모든 패키지의 메타데이터가 포함됩니다. 이는 pnpm을 포함한 모든 주요 Node.js 패키지 관리자에서 유지되는 표준입니다.
기존 package.json 형식 외에도 pnpm은 package.json5(json5 사용)와 package.yaml(js-yaml 사용)도 지원합니다.
참고
버전 v11부터 pnpm은 더 이상 package.json의 pnpm 필드에서 설정을 읽지 않습니다. 대신 설정은 pnpm-workspace.yaml에 정의해야 합니다. 설정하기를 참고하세요.
engines#
소프트웨어가 작동하는 Node 및 pnpm의 버전을 지정할 수 있습니다.
{
"engines": {
"node": ">=10",
"pnpm": ">=3"
}
}
로컬 개발 중에 버전이 engines 필드에 지정된 버전과 일치하지 않으면 pnpm은 항상 오류 메시지와 함께 실패합니다.
사용자가 engineStrict 설정 플래그(설정 참고)를 지정하지 않은 한, 이 필드는 권고 사항일 뿐이며 패키지가 종속성으로 설치될 때 경고만 표시합니다.
engines.runtime#
버전 10.21.0에서 추가됨
종속성에 필요한 Node.js 런타임을 지정합니다. 선언되면 pnpm은 지정된 Node.js 버전을 자동으로 설치합니다.
{
"engines": {
"runtime": {
"name": "node",
"version": "^24.11.0",
"onFail": "download"
}
}
}
패키지가 런타임을 선언하면:
- CLI 앱의 경우: pnpm은 CLI를 필요한 Node.js 버전에 연결하여, 전역으로 설치된 Node.js 인스턴스와 관계없이 올바른 런타임을 사용하도록 보장합니다.
postinstall스크립트가 있는 패키지의 경우: 스크립트가 지정된 Node.js 버전으로 실행됩니다.
이는 올바르게 작동하기 위해 특정 Node.js 버전이 필요한 종속성에 특히 유용합니다.
devEngines.runtime#
추가된 버전: v10.14
프로젝트에서 사용하는 하나 이상의 JavaScript 런타임 엔진을 지정할 수 있습니다. 지원되는 런타임은 Node.js, Deno, Bun입니다.
예를 들어, 다음과 같이 종속성에 node@^24.4.0을 추가할 수 있습니다:
{
"devEngines": {
"runtime": {
"name": "node",
"version": "^24.4.0",
"onFail": "download"
}
}
}
같은 package.json에 여러 런타임을 추가할 수도 있습니다:
{
"devEngines": {
"runtime": [
{
"name": "node",
"version": "^24.4.0",
"onFail": "download"
},
{
"name": "deno",
"version": "^2.4.3",
"onFail": "download"
}
]
}
}
작동 방식:
pnpm install은 지정한 범위를 일치하는 최신 런타임 버전으로 해석합니다.- 정확한 버전(및 체크섬)은 lockfile에 저장됩니다.
- 스크립트는 로컬 런타임을 사용하므로 환경 간 일관성이 보장됩니다.
매니페스트를 수정하지 않고 선언된 onFail 동작을 재정의하려면 runtimeOnFail 설정을 사용하세요.
버전 v12.0.0-rc.2부터는 스크립트뿐만 아니라 프로젝트 내부에서 직접 실행하는 node(또는 deno/bun)도 이 고정 버전을 따릅니다. 이 동작은 globalShims 설정으로 끌 수 있으며, PNPM_SHIM_BYPASS=1로 단일 명령에서만 건너뛸 수도 있습니다. 프로젝트 인식 전역 바이너리를 참고하세요.
devEngines.packageManager#
추가된 버전: v11.0.0
package.json의 devEngines.packageManager를 통해 pnpm 버전을 지정할 수 있습니다. packageManager 필드와 달리 버전 범위를 지원합니다. 해석된 버전은 pnpm-lock.yaml의 packageManagerDependencies 아래에 저장되며, 여전히 범위를 만족하면 재사용됩니다.
{
"devEngines": {
"packageManager": {
"name": "pnpm",
"version": ">=11.0.0 <12.0.0",
"onFail": "download"
}
}
}
참고
레거시 packageManager 필드(devEngines.packageManager가 아님)로 pnpm을 선언한 경우, 해석 정보는 기록되지 않습니다 — 즉, pnpm-lock.yaml에 저장되지 않으며, 고정된 pnpm 버전이 v12 이상인 경우만 예외입니다. 이를 통해 프로젝트가 레거시 필드를 강제로 버리지 않고도 pnpm v10에서 v11로 업그레이드할 때 lockfile을 안정적으로 유지할 수 있습니다.
버전 v12.0.0-rc.6부터 이 필드에는 다른 패키지 관리자인 npm, yarn 또는 bun도 지정할 수 있으며, pnpm add npm@11이 기록하는 것이 바로 이 값입니다. 이 경우 pnpm-lock.yaml에는 아무것도 기록되지 않습니다: packageManagerDependencies는 pnpm 자체의 고정 버전을 담고, 다른 패키지 관리자는 pnpm 홈 아래의 자체 환경 lockfile에 고정됩니다.
매니페스트를 수정하지 않고 onFail 동작을 재정의하려면 pmOnFail 설정을 참고하세요.
dependenciesMeta#
dependencies, optionalDependencies 및 devDependencies 내부에 선언된 종속성을 위한 추가적인 메타 정보입니다.
dependenciesMeta.*.injected#
로컬 워크스페이스 패키지인 종속성에 대해 이 값을 true로 설정하면, 해당 패키지는 가상 스토어(node_modules/.pnpm)에 하드 링크된 복사본을 생성하는 방식으로 설치됩니다.
이 값을 false로 설정하거나 설정하지 않으면, 종속성은 대신 워크스페이스에 있는 패키지의 소스 디렉터리를 가리키는 node_modules 심볼릭 링크를 생성하는 방식으로 설치됩니다. 이 방식이 더 빠르고 종속성의 변경 사항이 사용하는 쪽에 즉시 반영되므로 기본값입니다.
예를 들어, 다음 package.json이 로컬 워크스페이스 패키지라고 가정해 보겠습니다:
{
"name": "card",
"dependencies": {
"button": "workspace:1.0.0"
}
}
button 종속성은 일반적으로 card의 node_modules 디렉터리에 button의 개발 디렉터리를 가리키는 심볼릭 링크를 생성하는 방식으로 설치됩니다.
그런데 button이 peerDependencies에 react를 지정한다면 어떻게 될까요? 모노레포의 모든 프로젝트가 같은 버전의 react를 사용한다면 문제가 없습니다. 하지만 react@16을 사용하는 card와 react@17을 사용하는 form이 모두 button을 필요로 한다면 어떻게 될까요? 일반적으로는 react의 단일 버전을 선택하고 button의 devDependencies를 사용하여 지정해야 합니다. 심볼릭 링크 방식으로는 card와 form처럼 서로 다른 사용처에서 react 피어 종속성을 다르게 충족시킬 방법이 없습니다.
injected 필드는 가상 스토어에 button의 하드 링크된 복사본을 설치하여 이 문제를 해결합니다. 이를 위해 card의 package.json을 다음과 같이 설정할 수 있습니다:
{
"name": "card",
"dependencies": {
"button": "workspace:1.0.0",
"react": "16"
},
"dependenciesMeta": {
"button": {
"injected": true
}
}
}
반면 form의 package.json은 다음과 같이 설정할 수 있습니다:
{
"name": "form",
"dependencies": {
"button": "workspace:1.0.0",
"react": "17"
},
"dependenciesMeta": {
"button": {
"injected": true
}
}
}
이러한 변경으로 button은 card와 form의 "주입된 종속성"이 됩니다. button이 react를 import하면, react@16으로 해석되는 것은 card의 컨텍스트에서이고, react@17로 해석되는 것은 form의 컨텍스트에서입니다.
주입된 종속성은 워크스페이스 소스 디렉터리의 복사본을 만들기 때문에, 코드가 수정될 때마다 이 복사본을 어떤 방식으로든 업데이트해야 합니다. 그렇지 않으면 새로운 상태가 사용하는 쪽에 반영되지 않습니다. pnpm --recursive run build와 같은 명령으로 여러 프로젝트를 빌드할 때, 이 업데이트는 각 주입된 패키지가 다시 빌드된 후, 그리고 이를 사용하는 패키지가 다시 빌드되기 전에 이루어져야 합니다. 간단한 경우에는 pnpm install을 다시 실행하여 처리할 수 있으며, 해당 프로젝트 하나를 다시 빌드하기 위해 package.json의 "prepare": "pnpm run build"와 같은 라이프사이클 스크립트를 사용할 수도 있습니다. 서드파티 도구인 pnpm-sync와 pnpm-sync-dependencies-meta-injected는 주입된 종속성을 업데이트하는 더 안정적이고 효율적인 방법과 함께 watch 모드도 지원합니다.
peerDependencies#
피어 종속성 값은 일반적으로 semver 범위(^1.0.0)이거나 workspace: 또는 catalog: 지정자입니다.
버전 v11.14.0부터는 스킴이 포함된 지정자로도 피어 종속성을 선언할 수 있습니다:
{
"peerDependencies": {
"lib-a": "work:5.x.x",
"lib-b": "npm:other-lib@^5",
"lib-c": "file:../lib-c",
"lib-d": "git+https://example.com/lib-d.git"
}
}
허용되는 형식은 이름 있는 레지스트리 지정(<registry>:<version>), npm: 별칭, 그리고 file:, git 또는 URL 지정입니다.
이러한 지정자는 포함된 semver 범위를 기준으로 비교됩니다 — work:5.x.x는 5.x.x로, npm:other-lib@^5는 ^5로 검사됩니다. file:../lib-c처럼 버전이 없는 지정자는 *와 비교되므로 어떤 버전이든 이를 만족합니다. 한편 autoInstallPeers가 누락된 피어를 설치할 때는 원래 지정자로 패키지를 선택하므로, 피어는 지정한 별칭 이름, 레지스트리 또는 소스에서 가져옵니다.
단순한 name@version 값은 거의 항상 실수이므로 여전히 ERR_PNPM_INVALID_PEER_DEPENDENCY_SPECIFICATION 오류와 함께 거부됩니다:
{
"peerDependencies": {
"lib-a": "lib-a@1.2.3"
}
}
peerDependenciesMeta#
이 필드는 peerDependencies 필드에 작성된 의존성과 관련된 몇 가지 추가 정보를 나타냅니다.
peerDependenciesMeta.*.optional#
이 값을 true로 설정하면 선택한 피어 종속성이 패키지 관리자에 의해 선택 사항으로 표시됩니다. 따라서 소비자가 이를 생략하는 경우 오류가 보고되지 않습니다."
예시:
{
"peerDependencies": {
"foo": "1"
},
"peerDependenciesMeta": {
"foo": {
"optional": true
},
"bar": {
"optional": true
}
}
}
peerDependencies에 bar가 지정되지 않았더라도 선택 사항으로 표시된다는 점에 유의하세요. 따라서 pnpm은 bar의 모든 버전이 괜찮다고 가정합니다. 그러나 foo는 선택 사항이지만, 필수 버전 사양에 대해서만 해당됩니다.
publishConfig#
패키지가 압축되기 전에 매니페스트의 일부 필드를 재정의할 수 있습니다. 다음 필드를 재정의할 수 있습니다.
binmainexportstypes또는typingsmodulebrowseresnextes2015unpkgumd:maintypesVersions- cpu
- os
engines(추가된 버전: v10.22.0)name(추가된 버전: v11.18.0)
필드를 재정의하려면 필드의 게시 버전을 publishConfig에 추가합니다.
예를 들어, package.json은 다음과 같습니다.
{
"name": "foo",
"version": "1.0.0",
"main": "src/index.ts",
"publishConfig": {
"main": "lib/index.js",
"typings": "lib/index.d.ts"
}
}
다음과 같이 재정의 되어 게시됩니다.
{
"name": "foo",
"version": "1.0.0",
"main": "lib/index.js",
"typings": "lib/index.d.ts"
}
publishConfig.name#
추가된 버전: v11.18.0
워크스페이스의 매니페스트에 있는 이름과 다른 이름으로 패키지를 게시합니다. 이는 게시할 이름을 이미 형제 프로젝트가 사용하고 있어서, 그렇지 않으면 게시 직전에 빌드 단계에서 이름을 바꿔야 하는 프로젝트를 위한 것입니다.
{
"name": "foo-v2",
"version": "2.0.0",
"publishConfig": {
"name": "foo"
}
}
게시되는 아티팩트의 이름만 바뀝니다 — 의존하는 패키지, pnpm-lock.yaml, 릴리스 도구는 계속 매니페스트 이름으로 프로젝트를 참조합니다. 새 이름은 패킹된 매니페스트, tarball 파일 이름, 그리고 레지스트리에서 패키지를 참조하는 모든 곳에 적용됩니다: pnpm publish -r의 이미 게시되었는지 여부 확인 및 레지스트리 선택, 그리고 pnpm change status와 pnpm version -r의 릴리스 계획 조회가 이에 해당합니다.
publishConfig.executableFiles#
기본적으로, 이식성을 위해, bin 필드에 나열된 파일을 제외한 어떤 파일도 결과 패키지 아카이브에서 실행 가능한 것으로 표시되지 않습니다. executableFiles 필드를 사용하면 bin 필드를 통해 직접 접근할 수 없더라도 실행 플래그(+x)가 설정되어야 하는 추가 파일을 선언할 수 있습니다.
{
"publishConfig": {
"executableFiles": [
"./dist/shim.js"
]
}
}
publishConfig.directory#
또한 필드 publishConfig.directory를 사용하여 현재 package.json을 기준으로 게시된 하위 디렉터리를 커스터마이징 할 수 있습니다.
지정된 디렉터리에는 현재 패키지의 수정된 버전이 있어야 합니다(일반적으로 서드파티 빌드 도구를 사용합니다).
이 예시에서
"dist"폴더에는package.json이 포함되어야 합니다.
{
"name": "foo",
"version": "1.0.0",
"publishConfig": {
"directory": "dist"
}
}
publishConfig.linkDirectory#
- 기본값: true
- 유형: Boolean
true로 설정된 경우, 로컬 개발 중에 프로젝트가 publishConfig.directory 위치에서 심볼릭 링크됩니다.
예시:
{
"name": "foo",
"version": "1.0.0",
"publishConfig": {
"directory": "dist",
"linkDirectory": true
}
}