현록

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 cici는 npm 문서에서 clean install을 뜻한다.
이름처럼 기존 설치 결과를 믿지 않고 lock 파일 기준으로 깨끗하게 다시 설치한다.

npm ci

node_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.json

lock 파일이 없다면 npm cinpm 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.jsondependencies에 패키지를 추가하고 lock 파일도 갱신할 수 있다.
개발용 패키지는 -D 옵션으로 devDependencies에 넣는다.

npm install -D vitest

dependenciesdevDependencies의 차이가 헷갈린다면 dependencies와 devDependencies 차이를 먼저 보면 좋다.

npm ci와 npm install의 차이

두 명령어의 차이는 아래처럼 정리할 수 있다.

기준npm installnpm ci
주 용도일반 설치와 의존성 변경재현 가능한 clean install
lock 파일 없음lock 파일을 만들 수 있음실패
package.json과 lock 불일치lock 파일을 갱신할 수 있음실패
node_modules 존재기존 상태를 활용할 수 있음먼저 제거
package.json 수정패키지 추가 시 수정 가능수정하지 않음
CI 사용가능하지만 덜 엄격함더 적합
주 용도
npm install
일반 설치와 의존성 변경
npm ci
재현 가능한 clean install
lock 파일 없음
npm install
lock 파일을 만들 수 있음
npm ci
실패
package.json과 lock 불일치
npm install
lock 파일을 갱신할 수 있음
npm ci
실패
node_modules 존재
npm install
기존 상태를 활용할 수 있음
npm ci
먼저 제거
package.json 수정
npm install
패키지 추가 시 수정 가능
npm ci
수정하지 않음
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를 먼저 검토한다.

참고 자료

관련 포스트
HTML div와 span 차이 thumbnail
HTML div와 span 차이
HTML div와 span의 차이를 기본 display, 담을 수 있는 내용, 시맨틱 태그, CSS와 JavaScript에서 그룹화하는 기준으로 정리합니다.
HTTP 상태 코드 정리 thumbnail
HTTP 상태 코드 정리
HTTP 상태 코드의 2xx, 3xx, 4xx, 5xx 의미와 200, 201, 204, 301, 304, 400, 401, 403, 404, 500, 502, 503 차이를 정리합니다.
HTML id와 class 차이 thumbnail
HTML id와 class 차이
HTML id와 class의 차이를 문서 내 유일성, 여러 값 사용, CSS 선택자, JavaScript 탐색, fragment 링크와 이름 작성 기준으로 정리합니다.
HTML button과 a 태그 차이 thumbnail
HTML button과 a 태그 차이
HTML button과 a 태그의 차이를 이동과 동작의 의미, href, type 속성, 폼 제출, 키보드 접근성, 잘못된 사용 패턴으로 정리합니다.
HTTP GET과 POST 차이 thumbnail
HTTP GET과 POST 차이
HTTP GET과 POST의 차이를 초보자 기준으로 정리합니다. 조회와 변경, query string과 request body, 캐시, safe, idempotent, form과 fetch 사용 기준을 함께 봅니다.
npm outdated와 npm update 차이 thumbnail
npm outdated와 npm update 차이
npm outdated와 npm update의 차이를 초보자 기준으로 정리합니다. Current, Wanted, Latest의 의미와 semver 범위 안에서 업데이트되는 방식, package-lock.json 변화까지 함께 봅니다.
npm install -g와 npx 차이 thumbnail
npm install -g와 npx 차이
npm install -g와 npx의 차이를 초보자 기준으로 정리합니다. 전역 설치, 로컬 설치, 일회성 실행, 프로젝트 scripts에 넣는 기준까지 함께 봅니다.
package.json에서 ^와 ~ 차이 thumbnail
package.json에서 ^와 ~ 차이
package.json 의존성 버전 앞에 붙는 ^와 ~의 차이를 초보자 기준으로 정리합니다. semantic versioning, 버전 범위, 0.x 예외, package-lock.json과의 관계까지 함께 봅니다.
Git merge와 rebase 차이 thumbnail
Git merge와 rebase 차이
Git merge와 rebase가 커밋 그래프를 어떻게 바꾸는지 정리합니다. fast-forward, merge commit, rebase의 커밋 ID 변경, 충돌 처리, 공유 브랜치에서의 안전한 사용 기준까지 살펴봅니다.
npx와 npm exec 차이 thumbnail
npx와 npm exec 차이
npx와 npm exec가 어떤 명령어인지 초보자 기준으로 정리합니다. 로컬 패키지 실행, 원격 패키지 임시 실행, --package 옵션, -- 인자 전달 차이까지 함께 봅니다.
npm scripts와 npm run 정리 thumbnail
npm scripts와 npm run 정리
npm scripts란 무엇인지, package.json scripts와 npm run의 관계를 초보자 기준으로 정리합니다. npm run dev, npm start, npm test, node_modules/.bin, -- 인자 전달 방식까지 함께 봅니다.
dependencies와 devDependencies 차이 thumbnail
dependencies와 devDependencies 차이
package.json의 dependencies와 devDependencies 차이를 초보자 기준으로 정리합니다. npm install과 npm install -D, 배포 환경 설치, package-lock.json과의 관계까지 함께 봅니다.
.npmrc 파일이란? thumbnail
.npmrc 파일이란?
storybook을 사용해보려고 하다 마주한 이슈의 해결법을 알아보다가 등장한 .npmrc라는 파일에 대해 공부해보았다. .npmrc 파일이란? .npmrc 파일은 npm에 대한 config 파일이다. (npm에 대한 rc 파일) 프로젝트별 registry, install 옵션, 인증 토큰처럼 npm CLI가 읽는 설정을 관리할 때 사용한다.
스토리북이란? thumbnail
스토리북이란?
Storybook은 UI 컴포넌트를 독립적으로 개발하고, 문서화하고, 테스트하기 위한 프론트엔드 워크샵입니다. Storybook 10.4 기준 설치 흐름과 stories, 문서화, 테스트 활용 방식을 정리합니다.
TTV와 TTI 차이 thumbnail
TTV와 TTI 차이
TTV와 TTI의 차이를 초보자 기준으로 정리합니다. 사용자가 화면을 보는 시점, 상호작용 가능한 시점, FCP, LCP, INP, Core Web Vitals와의 관계까지 함께 봅니다.
Maria DB 외부 접속 설정하기 thumbnail
Maria DB 외부 접속 설정하기
안녕하세요. 오늘은 Maria DB 초기 세팅 시, 외부에서 접속이 안될 때 매뉴얼을 작성해보겠습니다. dotenv 패키지를 통해서 환경변수로 관리한다면, 별도의 추가 작업을 할 일이 없으실 겁니다.
package-lock.json 파일의 역할 thumbnail
package-lock.json 파일의 역할
안녕하세요. 오늘은 node 환경의 개발자라면 한번쯤 궁금했을만한 package-lock.json의 역할에 대해 알아보겠습니다. 우리는 node 환경에서 개발을 할 때 다양한 패키지들을 설치하여 활용하곤 합니다. 우리가 설치하는 패키지 또한 다른 npm 패키지를 활용하여 만든 패키지들이고 이들 또한 설치를 하게 됩니다. 이렇게 직간접적으로 설치된 패키지들은 대부분 호환성을 "^1.1.5"와 같이 표현하여, 범위로 지정해두고 있습니다.
Linux 환경 배포 자동화 체험해보기 thumbnail
Linux 환경 배포 자동화 체험해보기
안녕하세요. 요즘 포트폴리오를 만들면서 서버 상에 자주 반영할 일이 생겼는데, 매번 명령어들을 타이핑하는 것이 비효율적이라 생각이 들어 배포 자동화를 생각해보게 되었습니다. 현재 레벨에서는 단순히 명령어들만 단축시켜도 효율적이라 생각이 들어 간단한 쉘 스크립트만 작성하였습니다. 정말 간단하니 여러분도 도전해보시길 바랍니다.
협업 필수품. Prettier thumbnail
협업 필수품. Prettier
안녕하세요. 오늘은 Prettier이라는 도구에 대해 알려드리고자 합니다. 개발자는 각자의 코딩스타일이 존재합니다. 그러다보니 같은 프로젝트에서도 작성하는 소스마다 스타일이 제각기 다르기 일쑤입니다. 그럴 때 도입하면 좋은 것이 Prettier입니다. 프로젝트 root 폴더에 .prettierrc 라는 파일을 생성한 뒤, 위 예시와 같이 원하는 옵션을 JSON 형식으로 작성해주면 됩니다.