유의적 버전(SemVer): ^와 ~, 그리고 1.2.3의 의미
"react": "^18.2.0" 의 ^는 무슨 뜻일까요? 의존성 버전 표기를 이해하면 "업데이트했더니 깨졌다" 사고를 줄일 수 있습니다.
MAJOR.MINOR.PATCH
유의적 버전(Semantic Versioning)은 1.2.3 형태로, 각 자리가 약속을 담습니다.
| 자리 | 올라가는 경우 | 호환성 |
|---|---|---|
| MAJOR (1) | 호환 깨지는 변경 | 코드 수정 필요할 수 있음 |
| MINOR (2) | 기능 추가(하위 호환) | 안전 |
| PATCH (3) | 버그 수정 | 안전 |
즉 1.x.x → 2.0.0은 "기존 코드가 깨질 수 있으니 주의"라는 공식 신호입니다.
^ 와 ~ 의 차이
package.json의 범위 표기가 어디까지 자동 업데이트를 허용할지 정합니다.
"^1.2.3" → 1.2.3 이상, 2.0.0 미만 (MINOR·PATCH 허용)
"~1.2.3" → 1.2.3 이상, 1.3.0 미만 (PATCH만 허용)
"1.2.3" → 정확히 1.2.3만
^는 "호환되는 새 기능까지 받겠다", ~는 "버그 수정만 받겠다"는 보수적 선택입니다.
예외: 0.x.x 버전대에서는 ^0.2.3이 0.3.0 미만으로 묶입니다. 1.0.0 이전엔 MINOR도 깨질 수 있다고 보기 때문입니다.
lock 파일이 진짜 설치 버전을 고정한다
범위 표기는 "허용 범위"일 뿐, 실제 설치된 정확한 버전은 package-lock.json(또는 yarn.lock)에 박힙니다. 그래서:
- lock 파일은 반드시 커밋합니다(팀·CI가 동일 버전을 설치)
- 재현 가능한 설치는
npm ci(lock 그대로 설치, 빠르고 엄격)
안전하게 업데이트하기
npm outdated # 무엇이 구버전인지 확인
npm update # 범위 내에서 최신으로(^,~ 규칙 준수)
npm install pkg@latest # MAJOR까지 올릴 땐 의도적으로
MAJOR 업그레이드는 변경 로그(CHANGELOG)와 마이그레이션 가이드를 먼저 읽고, 별도 브랜치에서 테스트하세요.
마무리 체크리스트
MAJOR=호환 깨짐,MINOR=기능,PATCH=수정^=MINOR까지,~=PATCH만- lock 파일은 커밋, CI는
npm ci - MAJOR 올릴 땐 CHANGELOG 먼저
버전 숫자는 "이걸 올려도 안전한가?"에 대한 작성자의 약속입니다. 약속의 문법을 알면 업데이트가 덜 무섭습니다.
함께 보면 좋은 글
console.log를 넘어서: 더 빠르게 디버깅하는 7가지 방법
console.table·console.dir·조건부 중단점·watch 표현식·네트워크 탭까지. 무작정 로그를 찍는 대신 원인을 빠르게 좁히는 디버깅 습관을 정리합니다.
git stash 제대로 쓰기: 작업 중 급하게 브랜치 바꿀 때
작업 중인 변경을 커밋하지 않고 잠시 치워두는 git stash. save·pop·list·apply·drop의 차이와, 특정 파일만 stash하는 실전 패턴까지 정리합니다.
코드리뷰 잘하는 법 (팀이 성장하는 리뷰 vs 감정 상하는 리뷰)
코드리뷰는 코드를 고치는 일이 아니라 사람과 협업하는 일입니다. 리뷰어와 작성자 모두를 위한 실전 매너, 좋은 코멘트와 나쁜 코멘트 비교, 그리고 리뷰 속도를 높이는 팁을 정리했습니다.