본문으로 건너뛰기
Advertisement

Node.js 패키지 관리

패키지 관리자란?

Node.js 생태계에서 외부 라이브러리(패키지)를 설치·관리·공유하는 도구입니다. 패키지 메타데이터는 package.json에 기록되고, 실제 코드는 node_modules/에 저장됩니다.


npm vs yarn vs pnpm 비교

특징npmyarn (v1 Classic)pnpm
출시201020162017
기본 포함Node.js 번들별도 설치별도 설치
설치 속도보통빠름 (병렬)매우 빠름
디스크 사용많음많음적음 (심링크)
워크스페이스지원지원지원 (우수)
보안보통더 엄격엄격
락 파일package-lock.jsonyarn.lockpnpm-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: CommonJS require() 진입점
  • module: ESM import 진입점 (번들러용)
  • 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항상런타임에 필요한 패키지
devDependenciesnpm 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에 설정
Advertisement