CI/CD
CI에서 npm install 대신 npm ci를 써야 하는 이유
npm ci는 package-lock.json을 기준으로 정확히 설치하고 일관성을 보장한다. CI 환경에서 npm install을 쓰면 lockfile과 달라진 패키지가 들어올 수 있다.
GitHub Actions에서 Node.js 프로젝트를 빌드할 때 npm install을 쓰는 경우가 있다. 로컬에서 쓰던 명령이라 익숙해서다. CI에서는 npm ci가 맞다. 차이가 있다.
npm install과 npm ci의 차이
| npm install | npm ci | |
|---|---|---|
| lockfile 기준 | package.json과 lockfile 모두 참조, 불일치 시 lockfile 업데이트 | package-lock.json 그대로 설치 |
| lockfile 없을 때 | 생성함 | 에러로 종료 |
| lockfile과 package.json 불일치 | lockfile을 수정해서 맞춤 | 에러로 종료 |
| node_modules 처리 | 기존 디렉토리 유지, 증분 설치 | 삭제 후 완전히 새로 설치 |
npm ci는 항상 node_modules를 지우고 다시 설치하기 때문에 이전 실행의 잔여물이 없다. 그리고 package-lock.json에 명시된 정확한 버전만 설치한다.
실제로 문제가 생기는 경우
로컬에서 npm install some-package를 실행하면서 package-lock.json이 업데이트됐는데, 이걸 커밋에 포함하지 않은 채 push하는 경우가 있다. CI에서 npm install을 쓰면 이 상황에서 조용히 다른 버전을 설치할 수 있다.
npm ci라면 lockfile과 package.json의 불일치를 감지해서 바로 에러를 낸다.
npm ERR! cipm can only install packages when your package.json and
npm ERR! package-lock.json or npm-shrinkwrap.json are in sync.
이 에러가 뜨면 로컬에서 lockfile을 올바르게 생성해서 다시 push해야 한다는 신호다.
GitHub Actions 설정 예시
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm' # node_modules 캐시
- run: npm ci
- run: npm run build
- run: npm test
actions/setup-node의 cache: 'npm'을 함께 쓰면 ~/.npm 캐시를 재사용해서 설치 속도를 높일 수 있다. npm ci는 node_modules를 지우지만 npm 글로벌 캐시는 유지하기 때문에 캐시와 함께 써도 문제없다.
로컬에서 npm ci를 쓰면 안 되나
써도 된다. 로컬에서 완전히 깨끗한 설치 상태로 테스트하고 싶을 때 유용하다. 다만 node_modules를 매번 지우기 때문에 개발 중에는 느리다. 일상적인 개발 중에는 npm install, CI에서는 npm ci가 실용적인 구분이다.