Tech Blog
Tech Blog
Docspackage-lock.json, 왜 커밋해야 하나
GitHub
Infra8분

package-lock.json, 왜 커밋해야 하나

의존성 버전을 고정하고 재현 가능한 빌드를 보장하는 방법

2025년 1월 26일
npmci-cddockerpackage-manager

"내 로컬에서는 되는데요?"

개발하다 보면 한 번쯤 듣게 되는 말입니다. 대부분 Node 버전 차이나 OS 문제를 의심하지만, 의외로 package-lock.json 때문인 경우가 많습니다.

왜 문제가 되나

package.json의 "lodash": "^4.17.0"은 4.17.0 이상 5.0.0 미만의 모든 버전을 허용한다는 의미입니다. 오늘 설치하면 4.17.21이 들어오고, 내일 설치하면 4.17.22가 들어올 수 있습니다. 대부분의 경우 문제가 없지만, 간혹 마이너 버전에 버그가 포함되면 로컬에서 정상 동작하던 코드가 CI 환경에서 실패하는 상황이 발생합니다.

package-lock.json은 설치된 패키지의 정확한 버전을 기록합니다. 이 파일이 있으면 어떤 환경에서 설치하든 동일한 버전이 설치됩니다.

커밋해야 하는 이유

  • 환경 일관성 — 모든 개발자의 로컬, CI 서버, 프로덕션 환경에서 동일한 버전을 사용합니다
  • 보안 — 2021년 ua-parser-js 패키지가 해킹되어 악성 코드가 배포된 사례가 있습니다. lock 파일을 사용하던 프로젝트는 영향을 받지 않았지만, 매번 최신 버전을 설치하던 프로젝트는 감염되었습니다
  • 디버깅 — 6개월 전 버그 리포트가 접수되어도 해당 시점의 의존성 상태를 정확히 복원할 수 있습니다

React, Vue, Next.js, TypeScript 등 주요 오픈소스 프로젝트 모두 lock 파일을 커밋합니다.

npm ci

CI 환경에서는 npm install 대신 npm ci를 사용합니다.

npm cinpm install
node_modules삭제 후 새로 설치기존 유지
lock 파일 수정수정하지 않음필요 시 수정
package.json 불일치에러 발생자동으로 조정

npm ci는 Clean Install의 약자입니다. lock 파일에 명시된 버전을 그대로 설치하고, package.json과 불일치가 있으면 에러를 발생시킵니다. 의존성 트리를 재계산하지 않기 때문에 설치 속도도 더 빠릅니다.

GitHub Actions

YAML
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
      - run: npm ci
      - run: npm run build
      - run: npm test

cache: 'npm' 옵션은 lock 파일을 기반으로 의존성을 캐싱합니다.

Docker

DOCKERFILE
FROM node:20-alpine
WORKDIR /app
 
COPY package.json package-lock.json ./
RUN npm ci --only=production
 
COPY . .
RUN npm run build
 
CMD ["node", "dist/main.js"]

package.json과 package-lock.json을 먼저 복사하면 Docker의 레이어 캐싱을 활용할 수 있습니다. 소스 코드가 변경되어도 의존성 파일이 동일하면 npm ci 단계를 캐시에서 재사용합니다.

lock 파일 충돌

여러 브랜치에서 의존성을 수정하면 lock 파일 충돌이 발생할 수 있습니다. 이 경우 수동으로 머지하려 하지 말고, 한쪽 버전을 선택한 뒤 재생성하는 것이 안전합니다.

Bash
git checkout --theirs package-lock.json
npm install
git add package-lock.json

예외

라이브러리를 개발할 때는 lock 파일을 커밋하지 않는 경우도 있습니다. 라이브러리 사용자가 자신의 프로젝트에서 별도의 lock 파일을 관리하기 때문입니다. 모노레포 환경에서는 루트 디렉토리에 하나의 lock 파일만 두는 것이 일반적입니다.

핵심은 간단합니다. lock 파일을 커밋하고, CI 환경에서는 npm ci를 사용하면 됩니다.

참고

  • npm Docs - package-lock.json
  • npm Docs - npm ci
  • Node.js Docker Best Practices
목차
  • 왜 문제가 되나
  • 커밋해야 하는 이유
  • npm ci
  • GitHub Actions
  • Docker
  • lock 파일 충돌
  • 예외
  • 참고