npm ci와 npm install 차이
Node 프로젝트에서 의존성을 설치할 때 npm install을 가장 먼저 배운다.
그런데 GitHub Actions, 배포 스크립트, CI 설정을 보면 npm ci를 쓰는 경우가 많다.
두 명령어는 모두 의존성을 설치하지만 목적이 다르다.npm install은 의존성을 추가하거나 lock 파일을 갱신할 수 있는 일반 설치 명령어다.npm ci는 이미 확정된 lock 파일을 기준으로 깨끗하고 재현 가능하게 설치하는 명령어다.
초보자 기준으로는 이렇게 나누면 된다.
로컬에서 패키지를 추가하거나 의존성 상태를 바꿀 때는 npm install을 쓴다.
CI, 테스트, 배포처럼 같은 결과를 반복해야 할 때는 npm ci를 우선 고려한다.
clean install의 의미
npm ci의 ci는 npm 문서에서 clean install을 뜻한다.
이름처럼 기존 설치 결과를 믿지 않고 lock 파일 기준으로 깨끗하게 다시 설치한다.
npm cinode_modules 폴더가 이미 있다면 npm ci는 설치 전에 node_modules를 제거한다.
그리고 package-lock.json이나 npm-shrinkwrap.json에 기록된 의존성 트리를 기준으로 설치한다.
이 방식은 로컬에서 꼬인 의존성 상태를 줄이는 데 도움이 된다.
특히 여러 사람이 같은 프로젝트를 다루거나, CI 서버가 매번 같은 결과를 만들어야 할 때 유리하다.
package-lock.json 조건
npm ci는 lock 파일이 있어야 사용할 수 있다.
대표적으로 package-lock.json이 필요하다.
package.json
package-lock.jsonlock 파일이 없다면 npm ci는 npm install처럼 새 lock 파일을 만들어주지 않는다.
대신 오류로 종료한다.
또 package.json의 의존성 선언과 lock 파일의 내용이 맞아야 한다.
예를 들어 package.json에는 새 패키지가 추가됐는데 package-lock.json이 갱신되지 않았다면 npm ci는 lock 파일을 고치지 않는다.
이 경우 설치를 실패시켜서 두 파일이 어긋났다는 사실을 알려준다.
이 동작은 CI에서 특히 중요하다.
개발자가 의존성을 바꾸고 lock 파일을 커밋하지 않았다면 배포 전에 바로 알아낼 수 있기 때문이다.
lock 파일 자체의 역할이 헷갈린다면 package-lock.json 파일의 역할을 같이 보면 좋다.
npm install의 역할
npm install은 일반적인 설치 명령어다.
프로젝트 의존성을 설치하고, 필요하면 package-lock.json을 만들거나 갱신할 수 있다.
npm install새 패키지를 추가할 때도 npm install을 사용한다.
npm install axios이 명령은 package.json의 dependencies에 패키지를 추가하고 lock 파일도 갱신할 수 있다.
개발용 패키지는 -D 옵션으로 devDependencies에 넣는다.
npm install -D vitestdependencies와 devDependencies의 차이가 헷갈린다면 dependencies와 devDependencies 차이를 먼저 보면 좋다.
npm ci와 npm install의 차이
두 명령어의 차이는 아래처럼 정리할 수 있다.
| 기준 | npm install | npm ci |
|---|---|---|
| 주 용도 | 일반 설치와 의존성 변경 | 재현 가능한 clean install |
| lock 파일 없음 | lock 파일을 만들 수 있음 | 실패 |
| package.json과 lock 불일치 | lock 파일을 갱신할 수 있음 | 실패 |
| node_modules 존재 | 기존 상태를 활용할 수 있음 | 먼저 제거 |
| package.json 수정 | 패키지 추가 시 수정 가능 | 수정하지 않음 |
| CI 사용 | 가능하지만 덜 엄격함 | 더 적합 |
- npm install
- 일반 설치와 의존성 변경
- npm ci
- 재현 가능한 clean install
- npm install
- lock 파일을 만들 수 있음
- npm ci
- 실패
- npm install
- lock 파일을 갱신할 수 있음
- npm ci
- 실패
- npm install
- 기존 상태를 활용할 수 있음
- npm ci
- 먼저 제거
- npm install
- 패키지 추가 시 수정 가능
- npm ci
- 수정하지 않음
- npm install
- 가능하지만 덜 엄격함
- npm ci
- 더 적합
npm install은 개발 중 의존성을 바꿀 때 자연스럽다.npm ci는 이미 확정된 의존성 상태를 그대로 설치해야 할 때 자연스럽다.
그래서 로컬 개발자는 패키지를 추가할 때 npm install을 쓰고, CI 서버는 테스트 전에 npm ci를 쓰는 구성이 흔하다.
CI에서 쓰는 이유
CI는 같은 저장소 상태에서 같은 결과를 만들어야 한다.
테스트가 어떤 날은 통과하고 어떤 날은 실패하면 신뢰하기 어렵다.
npm ci는 lock 파일을 기준으로 설치하므로 의존성 트리를 재현하기 좋다.
또 package.json과 lock 파일이 어긋나면 실패하므로, 커밋 누락을 빠르게 발견할 수 있다.
- run: npm ci
- run: npm test
- run: npm run build이런 흐름에서는 npm ci로 의존성을 맞춘 뒤 테스트와 빌드를 실행한다.
프로젝트 명령어가 어떻게 정의되어 있는지는 npm scripts와 npm run 정리를 함께 보면 좋다.
.npmrc 플래그 주의점
lock 파일을 만들 때 특정 npm 옵션을 사용했다면 npm ci에서도 같은 옵션이 필요할 수 있다.
예를 들어 legacy-peer-deps, install-links처럼 의존성 트리 모양에 영향을 주는 옵션이 여기에 해당한다.
이런 옵션을 매번 명령어에 붙이기보다 프로젝트의 .npmrc에 저장하고 함께 커밋하는 편이 좋다.
legacy-peer-deps=true그렇지 않으면 로컬에서 만든 lock 파일은 멀쩡해 보이는데 CI의 npm ci에서만 설치가 실패하는 상황을 만날 수 있다.
프로젝트 설정 파일 기준이 궁금하면 .npmrc 파일이란?을 같이 보면 좋다.
로컬에서 쓰는 기준
로컬에서 항상 npm ci만 써야 하는 것은 아니다.
패키지를 추가하거나 버전을 바꾸는 작업에는 npm install이 맞다.
npm install react
npm install -D eslint반대로 의존성 상태를 lock 파일 기준으로 다시 맞추고 싶다면 npm ci가 편하다.
npm ci예를 들어 node_modules가 꼬였거나, 다른 브랜치로 이동한 뒤 의존성 상태가 애매해졌다면 npm ci로 깨끗하게 맞출 수 있다.
다만 이 명령은 node_modules를 제거하고 다시 설치하므로 로컬에서 수정한 패키지 내부 파일이 있다면 사라진다.
정리
npm install은 의존성을 설치하고 변경할 수 있는 일반 명령어다.
패키지를 추가하거나 lock 파일을 갱신해야 하는 개발 작업에 잘 맞는다.
npm ci는 lock 파일을 기준으로 깨끗하게 설치하는 명령어다.
CI, 테스트, 배포처럼 같은 의존성 트리를 반복해서 설치해야 하는 환경에 잘 맞는다.
처음에는 기준을 단순하게 잡아도 된다.
의존성을 바꿀 때는 npm install이다.
의존성을 재현할 때는 npm ci다.
CI에서는 가능하면 npm ci를 먼저 검토한다.
참고 자료


















