가끔씩 같은 로직인데 프로젝트에서는 되고 내꺼에서는 안되는 일이 있습니다.
심지어 코드를 그대로 복붙해와서 모든게 똑같다고 해도 말이죠
이런 상황이 왜 발생할까요? 답은 버저닝(Versioning)과 캐럿(^), 그리고 우리가 잘 보지 못하는 의존성 버저닝에 있습니다.
버저닝의 기본: 시맨틱 버저닝(SemVer)
대부분의 오픈소스 패키지는 시맨틱 버저닝(SemVer) 이라는 규칙을 따릅니다.
형식은 다음과 같습니다.
MAJOR.MINOR.PATCH
- MAJOR (주버전): 기존과 호환되지 않는 큰 변경
- 예: API 구조가 바뀌어 기존 코드가 깨짐
- MINOR (부버전): 기존과 호환되는 기능 추가
- 예: 새로운 옵션이나 컴포넌트가 추가
- PATCH (수정버전): 버그 수정이나 작은 개선
- 예: 스타일 깨짐 수정, 크래시 버그 패치
예를 들어, 2.3.1은
- 2 → 큰 틀(major 버전)
- 3 → 새로운 기능 추가(minor 버전)
- 1 → 버그 수정(patch 버전)
이라는 의미를 갖습니다.
이 규칙 덕분에 우리는 버전 번호만 보고도 “이 업데이트가 위험할지, 단순 수정일지”를 가늠할 수 있습니다.
요런 농담도 있는데요
매우 인정합니다.

캐럿(^)이란 무엇인가?
package.json을 열어보면 이런 식으로 버전 앞에 기호가 붙어 있는 걸 자주 봅니다.
"my-library": "^1.2.3"
여기서 ^(캐럿)은 “호환되는 최신 버전을 자동으로 허용”하겠다는 의미입니다.
캐럿의 동작 규칙
- ^1.2.3 → >=1.2.3 <2.0.0
(메이저 버전이 바뀌지 않는 범위 내에서 최신 버전 허용) - ^0.2.1 → >=0.2.1 <0.3.0
(메이저가 0일 때는 보수적으로, 마이너까지만 허용) - ^0.0.3 → =0.0.3
(패치 버전 고정)
즉, 메이저 버전이 1 이상인 안정적인 라이브러리라면 캐럿을 사용해도 대부분 안전합니다.
하지만 0.x 버전대 라이브러리는 아직 불안정하기 때문에, 캐럿을 쓰면 위험할 수 있습니다.
하지만 이 버전 믿어도 될까? : “툴팁 Provider 사건”
그런데 어느 날 이런 문제가 발생했습니다. 대략 예시를 들어보겠습니다.
나는 ui-tooltips라는 라이브러리를 사용 중이었고, ^0.2.1로 설치해 두었습니다. (이런 라이브러리는 없습니다. 제가 가상으로 만든 겁니다. )
그런데 어느 날 갑자기 앱이 이렇게 크래시했습니다.
Error: InvalidContextUsage: Tooltip은 Provider 하위에서 사용해야 합니다
원인을 추적해보니…
- 0.2.1에서는 그냥 <Tooltip />을 쓰면 잘 동작했는데,
- 0.2.11에서 Provider를 반드시 감싸야 하는 규칙이 추가됐던 겁니다.
즉, 이렇게 바뀐 거죠.
// 예전(0.2.1)에는 그냥 됨
<Tooltip text="Hello" />
// 새 버전(0.2.11)부터는 이렇게 안 하면 에러
<TooltipProvider>
<Tooltip text="Hello" />
</TooltipProvider>
문제는 이 변화가 Patch 버전(0.2.11) 에 들어갔다는 것입니다.
시맨틱 버저닝 원칙상 호환성이 깨지는 변경은 Major나 최소한 Minor 버전에 들어가야 하는데, Patch로 들어가 버린 것이죠.
결과적으로, 내가 ^0.2.1을 쓰고 있었기 때문에 자동으로 0.2.11이 설치되었고, 예기치 못한 에러를 맞이하게 된 겁니다.
근데 만약 이 라이브러리가 제가 고칠 수 있는 것이 아니라면?
해결 방법은 단순합니다. 캐럿을 제거하고 버전을 고정하는 것이죠. (더 좋은 해결법은 아무래도 이런 일이 발생하면 안되는..)
"ui-tooltips": "0.2.1"
이렇게 하면 항상 동일한 버전을 쓰게 되어 안정성을 확보할 수 있습니다.
의존성 버저닝의 함정
문제는 내가 직접 설치한 라이브러리만 신경 쓴다고 끝이 아니라는 데 있습니다.
대부분의 라이브러리는 또 다른 라이브러리에 의존합니다. 즉, 의존성의 의존성(transitive dependency)이 존재합니다.
예를 들어, 내가 설치한 건 `abc` 라는 라이브러리인데, 실제로는 내부에서 `a` 라는 다른 라이브러리를 사용하고 있다고 합시다.
이 경우 `a`의 버저닝 정책에 문제가 있으면, 내가 직접 설치하지도 않은 코드 때문에 내 앱이 깨질 수 있습니다.
의존성 버전 확인 방법
이런 문제를 예방하려면 내 프로젝트에 어떤 버전의 라이브러리가 설치되어 있는지 확인하는 습관이 필요합니다.
npm
npm ls abc
yarn
yarn why abc
pnpm
pnpm why abc
이 명령어들을 통해 “이 라이브러리가 어떤 버전의 패키지들을 끌고 왔는지” 확인할 수 있습니다 !
만약 내가 가진 라이브러리 버전과 동일한데도 에러가 터진다면 요 라이브러리가 의존하는 다른 라이브러리가 문제가 될 수도 있는거죠 !!
교훈
이 사례는 제가 실제 최근 디버깅한 사례에서 따왔습니다..
평소 install 만하고 버전은 크게 신경쓰지 못했던 저에게 큰 러닝을 주었던 + 야근을 주었던 사례였습니다.
- Patch라고 무조건 안전하지 않다. (나도 실수할 수 있음. 잘 확인해야한다 !)
- 특히 0.x 버전대 라이브러리는 캐럿(^)을 쓰면 위험 → 버전 고정 권장
- 내가 직접 설치한 라이브러리뿐만 아니라, 그 라이브러리가 의존하는 서브 디펜던시까지 버저닝 리스크가 있다
언제나 믿었던 숫자도 휴먼에러를 가진 숫자일 수도 있습니다. 사람은 늘 실수를 하기 때문이죠
그래서 이번 기회로 버전 번호를 믿괴, 항상 확인하고 검증해보려는 러닝을 갖게 되었습니다 !!
끗 !
'Frontend' 카테고리의 다른 글
| Next.js에서 Google Form API 사용해서 데이터 수집하기 (3) | 2025.08.31 |
|---|