npm install 의존성 충돌 해결 완벽 가이드: legacy-peer-deps 옵션 실전 사용법

npm install 실행 시 ERESOLVE unable to resolve dependency tree 에러를 만난 적 있는가? React 18 업그레이드 후 특정 라이브러리 설치가 막히거나, peer dependency 충돌로 프로젝트가 멈춰버리는 상황은 생각보다 흔하다. 이 글에서는 --legacy-peer-deps 옵션의 정확한 의미와 함께, 근본 원인 해결부터 임시 우회까지 실전 트러블슈팅 시나리오를 정리한다.


npm install 안될 때 대처법: legacy-peer-deps부터 버전 관리까지 5단계 해결 전략




1. ERESOLVE 에러가 발생하는 근본 원인

npm v7부터는 peer dependency 충돌을 엄격하게 검사한다. 예를 들어 React 18 프로젝트에 @mui/styles를 설치하려 할 때, 해당 패키지가 react@^17.0.0을 요구하면 설치가 중단된다. 이는 npm이 의존성 트리를 해결(resolve)할 수 없다고 판단하기 때문이다.

  • 메이저 버전 불일치: React 17 전용 라이브러리를 React 18 환경에서 사용
  • 중첩된 peer dependency: 여러 패키지가 서로 다른 버전의 동일 라이브러리를 요구
  • React Native 환경: @react-native-community/async-storage처럼 구버전 React에 의존하는 패키지 사용 시

npm v6 이하에서는 peer dependency를 경고만 하고 넘어갔지만, v7+는 설치 자체를 차단한다. 이 변화를 이해하지 못하면 "갑자기 안 되는" 상황에 당황하게 된다.

2. --legacy-peer-deps vs --force: 차이점과 위험성

두 옵션 모두 충돌을 무시하고 설치를 강행하지만, 동작 방식이 다르다.

--legacy-peer-deps

  • npm v6 방식으로 동작: peer dependency 충돌을 경고만 하고 무시
  • 충돌하는 패키지를 루트 node_modules에 추가하지 않음
  • 상대적으로 안전하며, 대부분의 경우 앱이 정상 동작
npm install @mui/styles --legacy-peer-deps

--force

  • 충돌을 강제로 덮어쓰며 루트에 패키지 추가
  • 의존성 트리가 깨질 가능성이 높아 런타임 에러 발생 위험
  • React Native에서 --force 사용 후 앱이 렌더링조차 안 되는 사례 다수 보고됨

권장 우선순위: 버전 조정 > --legacy-peer-deps > --force 순으로 시도하라. --force는 최후의 수단이며, 사용 후 반드시 앱 전체 테스트가 필요하다.

3. .npmrc 설정으로 전역 적용하기

매번 옵션을 붙이기 번거롭다면, 프로젝트 루트에 .npmrc 파일을 생성하여 영구 적용할 수 있다.

# .npmrc
legacy-peer-deps=true

이후 모든 npm install 명령에서 자동으로 --legacy-peer-deps가 적용된다. 단, 이는 근본 해결이 아닌 임시 우회이므로, 가능한 한 패키지 버전을 맞추는 작업을 병행해야 한다.

4. 근본 해결: 의존성 정리 및 버전 관리 전략

--legacy-peer-deps는 임시방편일 뿐이다. 장기적으로는 아래 방법으로 의존성을 정리해야 한다.

4-1. npm-check-updates로 패키지 일괄 업데이트

npm i -g npm-check-updates
ncu -u
npm install

모든 패키지를 최신 버전으로 업데이트하여 호환성 문제를 해소한다. 단, breaking change가 있을 수 있으므로 업데이트 후 테스트 필수.

4-2. Node.js 버전 조정 (nvm 활용)

Node 17+ 환경에서 특정 패키지가 작동하지 않는 경우, Node 16.x로 다운그레이드하면 해결되는 경우가 많다.

node -v
nvm install 16.20.0
nvm use 16.20.0
npm install

또는 n 버전 매니저 사용:

sudo npm install -g n
n lts

4-3. React 버전과 라이브러리 호환성 체크

  • React 17 + React Router v5: 호환 OK
  • React 18 + React Router v6: 호환 OK
  • React 18 + React Router v5: URL 변경되나 페이지 렌더링 안 됨 (치명적)

React 18을 사용한다면 React Router를 v6로 업그레이드하거나, React를 17로 다운그레이드해야 한다. v6는 <Switch> 대신 <Routes>element={} 방식으로 변경되므로 마이그레이션 가이드를 참고하라.

React Query 사용 시 React 18에서는 @tanstack/react-query로 설치해야 TypeScript import 문제가 발생하지 않는다:

npm i @tanstack/react-query

5. React Native 환경 특화 이슈 해결

React Native에서 this package itself specifies a main module field that could not be resolved 에러가 발생하면, metro.config.js에서 CommonJS 확장자를 추가해야 한다.

// metro.config.js
module.exports = {
  resolver: {
    sourceExts: ['jsx', 'js', 'ts', 'tsx', 'cjs'],
  },
};

또한 stompjs 같은 패키지 설치 시 @react-native-community/async-storage가 React 16.8 의존성을 가져 충돌하는 경우, --legacy-peer-deps보다는 최신 대체 패키지로 교체하는 것을 권장한다.

6. 캐시 및 node_modules 초기화

의존성 충돌이 반복되면 캐시와 lock 파일을 삭제 후 재설치하라.

sudo npm cache clean -f
rm -rf node_modules/
rm -rf package-lock.json
npm install

권한 문제로 설치가 막힌다면 sudo npm install을 사용하되, 프로덕션 환경에서는 권한 설정을 먼저 점검해야 한다.

7. yarn으로 우회하는 방법

npm의 peer dependency 검사가 너무 엄격하다면, yarn을 사용하는 것도 대안이다. yarn은 충돌을 좀 더 유연하게 처리하며, 일부 사례에서 npm 에러 없이 설치가 성공한다.

yarn add @mui/styles

단, 팀 프로젝트라면 패키지 매니저를 통일해야 하므로, 임의로 변경하기 전에 합의가 필요하다.

결론 및 Action Item

--legacy-peer-deps는 npm v7+의 엄격한 peer dependency 검사를 우회하는 옵션이다. 하지만 이는 임시 조치일 뿐, 근본 원인은 패키지 버전 불일치에 있다. 권장 해결 순서는 다음과 같다:

  1. npm-check-updates로 패키지 버전 일괄 업데이트
  2. React 버전과 라이브러리(Router, Query 등) 호환성 체크
  3. Node.js 버전을 nvm으로 조정 (특히 16.x LTS)
  4. 그래도 안 되면 .npmrc에 legacy-peer-deps=true 추가
  5. React Native는 metro.config.js에 'cjs' 추가

지금 당장 실행할 것: 프로젝트 루트에서 ncu -u로 package.json을 업데이트하고, npm install을 재시도하라. 충돌이 지속되면 .npmrc에 legacy-peer-deps=true를 추가한 뒤, 반드시 앱 전체 테스트를 수행하라.


#함께 읽으면 좋은 글

Node.js EADDRINUSE 에러 해결 완벽 가이드 netstat과 lsof 실전 활용법 : 바로보기

댓글