Node.js 패키지 관리
패키지 관리자란?
Node.js 생태계에서 외부 라이브러리(패키지)를 설치·관리·공유하는 도구입니다. 패키지 메타데이터는 package.json에 기록되고, 실제 코드는 node_modules/에 저장됩니다.
npm vs yarn vs pnpm 비교
| 특징 | npm | yarn (v1 Classic) | pnpm |
|---|---|---|---|
| 출시 | 2010 | 2016 | 2017 |
| 기본 포함 | Node.js 번들 | 별도 설치 | 별도 설치 |
| 설치 속도 | 보통 | 빠름 (병렬) | 매우 빠름 |
| 디스크 사용 | 많음 | 많음 | 적음 (심링크) |
| 워크스페이스 | 지원 | 지원 | 지원 (우수) |
| 보안 | 보통 | 더 엄격 | 엄격 |
| 락 파일 | package-lock.json | yarn.lock | pnpm-lock.yaml |
명령어 비교
# 패키지 설치
npm install express
yarn add express
pnpm add express
# 개발 의존성
npm install --save-dev jest
yarn add --dev jest
pnpm add -D jest
# 전체 의존성 설치 (CI)
npm ci
yarn install --frozen-lockfile
pnpm install --frozen-lockfile
# 스크립트 실행
npm run build
yarn build
pnpm build
# 전역 설치
npm install -g pm2
yarn global add pm2
pnpm add -g pm2
# 패키지 제거
npm uninstall express
yarn remove express
pnpm remove express
# 업데이트
npm update
yarn upgrade
pnpm update
pnpm이 디스크를 절약하는 방법
npm/yarn 방식:
project-a/node_modules/lodash@4.17.21/ (복사본)
project-b/node_modules/lodash@4.17.21/ (복사본)
project-c/node_modules/lodash@4.17.21/ (복사본)
pnpm 방식:
~/.pnpm-store/lodash@4.17.21/ (한 개만 저장)
project-a/node_modules/lodash → 심볼릭 링크
project-b/node_modules/lodash → 심볼릭 링크
project-c/node_modules/lodash → 심볼릭 링크
package.json 필드 상세 설명
{
"name": "my-awesome-app",
"version": "1.2.3",
"description": "Node.js 애플리케이션 예제",
"main": "dist/index.js",
"module": "dist/index.esm.js",
"exports": {
".": {
"import": "./dist/index.esm.js",
"require": "./dist/index.cjs.js"
},
"./utils": "./dist/utils.js"
},
"type": "module",
"scripts": {
"start": "node dist/index.js",
"dev": "nodemon src/index.js",
"build": "tsc",
"test": "jest --coverage",
"test:watch": "jest --watch",
"lint": "eslint src/**/*.js",
"lint:fix": "eslint src/**/*.js --fix",
"format": "prettier --write src/**/*.js",
"prepare": "husky install",
"prepublishOnly": "npm run build && npm test"
},
"keywords": ["node", "express", "api"],
"author": {
"name": "김철수",
"email": "kim@example.com",
"url": "https://example.com"
},
"license": "MIT",
"homepage": "https://github.com/user/repo#readme",
"repository": {
"type": "git",
"url": "https://github.com/user/repo.git"
},
"bugs": {
"url": "https://github.com/user/repo/issues"
},
"engines": {
"node": ">=20.0.0",
"npm": ">=10.0.0"
},
"dependencies": {
"express": "^4.18.2",
"dotenv": "^16.3.1"
},
"devDependencies": {
"jest": "^29.7.0",
"nodemon": "^3.0.2",
"eslint": "^8.55.0"
},
"peerDependencies": {
"react": ">=18.0.0"
},
"optionalDependencies": {
"fsevents": "^2.3.3"
},
"files": [
"dist",
"README.md"
],
"private": true
}
주요 필드 설명
name: 패키지 이름, npm 레지스트리에서 고유해야 함 (스코프 가능:@myorg/pkg)version: SemVer 버전 (major.minor.patch)main: CommonJSrequire()진입점module: ESMimport진입점 (번들러용)exports: 정밀한 진입점 제어 (Node.js 12+)type:"module"설정 시.js파일이 ESM으로 처리됨files: npm publish 시 포함할 파일 목록private:true설정 시 실수로 publish 방지
의존성 종류
{
"dependencies": {
"express": "^4.18.2"
},
"devDependencies": {
"jest": "^29.7.0",
"nodemon": "^3.0.2",
"typescript": "^5.3.2",
"eslint": "^8.55.0"
},
"peerDependencies": {
"react": ">=18.0.0"
},
"optionalDependencies": {
"fsevents": "^2.3.3"
}
}
| 종류 | 설치 조건 | 용도 |
|---|---|---|
dependencies | 항상 | 런타임에 필요한 패키지 |
devDependencies | npm install (--production 제외) | 개발/빌드 도구 |
peerDependencies | 수동 (사용자가 설치) | 라이브러리 제작 시 호환 버전 선언 |
optionalDependencies | 실패해도 무시 | 플랫폼별 선택적 의존성 |
# 프로덕션만 설치 (devDependencies 제외)
npm install --production
# 또는 NODE_ENV=production npm install
버전 범위 지정
SemVer(Semantic Versioning): major.minor.patch
- major: 하위 호환 불가능한 변경 (breaking change)
- minor: 하위 호환 가능한 기능 추가
- patch: 버그 수정
{
"dependencies": {
"pkg-a": "4.18.2", // 정확히 이 버전만
"pkg-b": "^4.18.2", // 4.x.x (major 고정)
"pkg-c": "~4.18.2", // 4.18.x (minor 고정)
"pkg-d": ">=4.0.0", // 4.0.0 이상
"pkg-e": ">=4.0.0 <5.0.0",// 4.x.x 범위
"pkg-f": "*", // 최신 버전 (비권장)
"pkg-g": "latest", // 최신 버전 태그
"pkg-h": "4.x", // 4.x.x
"pkg-i": "git+https://github.com/user/repo.git", // Git URL
"pkg-j": "file:../local-package" // 로컬 경로
}
}
업데이트 정책 권장
# 현재 설치된 버전 확인
npm list --depth=0
# 업데이트 가능한 패키지 확인
npm outdated
# 안전한 업데이트 (patch, minor)
npm update
# major 업데이트 (주의 필요)
npm install express@latest
# 취약점 확인
npm audit
# 자동 수정
npm audit fix
package-lock.json과 yarn.lock의 역할
package.json → "대략 이 버전 써도 돼" (범위 지정)
package-lock.json → "정확히 이 버전 써" (고정)
package-lock.json 예시
{
"name": "my-app",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"node_modules/express": {
"version": "4.18.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
"integrity": "sha512-...",
"dependencies": {
"accepts": "~1.3.8",
"body-parser": "1.20.1"
}
}
}
}
중요 규칙:
package-lock.json은 반드시 git에 커밋node_modules/는.gitignore에 추가- CI/CD에서는
npm ci사용 (lock 파일 엄격 준수)
npm scripts 활용
{
"scripts": {
"start": "node src/index.js",
"dev": "nodemon src/index.js --watch src",
"build": "tsc -p tsconfig.json",
"clean": "rm -rf dist",
"prebuild": "npm run clean",
"postbuild": "echo 빌드 완료",
"test": "jest",
"test:ci": "jest --ci --coverage --forceExit",
"lint": "eslint src",
"format": "prettier --write 'src/**/*.{js,ts}'",
"typecheck": "tsc --noEmit",
"check": "npm run lint && npm run typecheck && npm test",
"docker:build": "docker build -t myapp .",
"docker:run": "docker run -p 3000:3000 myapp",
"db:migrate": "node scripts/migrate.js",
"db:seed": "node scripts/seed.js",
"db:reset": "npm run db:migrate && npm run db:seed"
}
}
특수 스크립트
# pre/post 훅
# prebuild → build → postbuild 순서로 자동 실행
# 환경 변수 전달
NODE_ENV=production npm run build
# 스크립트 인수 전달
npm run test -- --verbose --testNamePattern="User"
# jest --verbose --testNamePattern="User"
# npx로 로컬 패키지 실행
npx jest
npx ts-node src/index.ts
로컬 vs 전역 패키지
# 로컬 설치 (프로젝트 의존성)
npm install express
# → node_modules/express/ 에 저장
# → 프로젝트 내에서만 사용
# 전역 설치 (시스템 도구)
npm install -g pm2 nodemon typescript
# → 전역 경로에 저장 (which pm2 로 확인)
# → 어디서든 CLI로 사용 가능
# 전역 설치 목록 확인
npm list -g --depth=0
# 전역 설치 경로
npm root -g
npm bin -g
# 권장: 전역 대신 npx 사용
npx create-next-app my-app
npx nodemon server.js
.npmrc 설정
# .npmrc (프로젝트 루트 또는 홈 디렉토리)
# 레지스트리 설정
registry=https://registry.npmjs.org/
# 스코프별 레지스트리 (사설 레지스트리)
@mycompany:registry=https://npm.mycompany.com/
# 로그 레벨
loglevel=warn
# 저장 방식
save-exact=true # ^ 없이 정확한 버전 저장
save-prefix=~ # ^대신 ~ 사용
# 캐시 경로
cache=/tmp/npm-cache
# 프록시 설정 (회사 환경)
# proxy=http://proxy.company.com:8080
# https-proxy=http://proxy.company.com:8080
# 패키지 잠금
package-lock=true
# 오프라인 모드
# offline=true
# 인증 토큰 (GitHub Packages 등)
# //npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}
고수 팁
workspaces (모노레포)
// 루트 package.json
{
"name": "my-monorepo",
"private": true,
"workspaces": [
"packages/*",
"apps/*"
]
}
# 특정 워크스페이스에 패키지 설치
npm install express --workspace=apps/api
# 특정 워크스페이스 스크립트 실행
npm run build --workspace=packages/ui
# 모든 워크스페이스 스크립트 실행
npm run build --workspaces
패키지 보안 검사
# 취약점 검사
npm audit
# JSON 형식 출력
npm audit --json
# 수정 가능한 취약점 자동 수정
npm audit fix
# 강제 수정 (주의: major 업데이트 포함)
npm audit fix --force
# 특정 패키지 취약점 무시 (임시)
# .nsprc 또는 .npmrc에 설정