Calendar Version이란 ?
들어가며
회사 프론트엔드 CICD 를 만지다가, 시멘틱 버전 및 릴리즈 노트가 어느순간 CI 에서 깨지고 있는 것을 발견했다. 현재 우리 전반적인 프론트엔드 프로젝트는 커밋의 Subject 를 기준으로 시멘틱버전으로 관리되고, 이미지 태그에 해당 버전이 붙었다.
“웹 프로젝트에 시멘틱 버저닝이 정말 필요할까?”
API 를 제공하는 라이브러리나 패키지라면 1.2.3 같은 버전이 의미가 있다. 하위 호환성 여부, 브레이킹 체인지 여부를 외부 사용자가 바로 알 수 있어야 하기 때문이다. 그런데 팀 내부에서만 쓰는 웹 서비스라면? CI/CD로 main 브랜치가 머지될 때마다 자동으로 배포되는 구조라면?
이 질문을 가지고 이것저것 찾아보다가 Calendar Versioning(CalVer) 을 알게 됐다.
시멘틱 버저닝 복습
CalVer 를 이야기하기 전에, 시멘틱 버저닝(SemVer) 부터 짚고 넘어가자.
SemVer 는 MAJOR.MINOR.PATCH 형식을 따른다.
1.4.2
│ │ └── PATCH: 버그 픽스 (하위 호환 O)
│ └──── MINOR: 새 기능 추가 (하위 호환 O)
└────── MAJOR: 브레이킹 체인지 (하위 호환 X)규칙이 명확하고 외부 사용자 입장에서 변경의 영향을 직관적으로 파악할 수 있다. npm, PyPI 등 패키지 에코시스템 전반에서 표준으로 자리 잡은 이유가 여기 있다.
그런데 웹 서비스에 적용하면 몇 가지 어색한 지점이 생긴다.
이 버전이 언제 배포된 건지 버전 번호만 봐서는 알 수 없다. ( 어쩌면 당연한건가 )
0.x.x단계가 너무 길어지거나, 반대로 MAJOR 가 너무 빠르게 올라간다. ( 필자의 프로젝트는 0 버전을 영원히 벗어난적이 없다. )이러한 이유로
1.82.92와 같은 마치 리액트 네이티브와 같은 버전 기괴한 버저닝이 나오게 된다.
Calendar Versioning 이란?
CalVer 는 버전 번호에 날짜 (출시일) 를 포함시키는 버저닝 방식이다.
공식 사이트는 calver.org 이며, 형식은 프로젝트마다 다양하게 적용된다.
근데 실제로도 여러 프로젝트에서 사용중인것을 확인할 수 있었습니다.
구성 요소
| 구분 | 표기 | 설명 | 예시 |
|---|---|---|---|
| 연도 | YYYY | 4 자리 연도 | 2026 |
| 연도 | YY | 2 자리 연도 | 26 |
| 월 | MM | 제로 패딩 월 | 05 |
| 월 | M | 제로 패딩 없는 월 | 5 |
| 일 | DD | 제로 패딩 일 | 02 |
| 마이크로 | MICRO | 동일 날짜의 n 번째 릴리즈 | 1, 2 |
| 수정자 | MODIFIER | 알파/베타/RC 등 | alpha, rc1 |
SemVer vs CalVer 비교
| 항목 | SemVer | CalVer |
|---|---|---|
| 형식 | MAJOR.MINOR.PATCH | 날짜 기반 |
| 출시 시기 파악 | 불가 | 즉시 가능 |
| 하위 호환성 신호 | 명확 (MAJOR) | 없음 |
| 외부 사용자 친화도 | 높음 | 보통 |
| 웹 서비스 적합도 | 어색할 수 있음 | 자연스러움 |
| CI/CD 자동화 | 수동 버전 관리 필요 | 날짜로 자동 생성 가능 |
TIPSemVer 와 CalVer 는 서로 경쟁 관계가 아니다. 혼합해서 쓰는 프로젝트도 많다. 예를 들어
2026.05.1처럼 날짜를 앞에 두고 뒤에 MICRO 버전을 붙이면 날짜 정보와 동일 날짜 내 순서를 동시에 표현할 수 있다.
웹 서비스에서 CalVer 가 어울리는 이유
처음 질문으로 돌아가서 — 웹 서비스에 시멘틱 버저닝이 굳이 필요한가?
웹 서비스는 대부분 다음과 같은 특성을 가진다. ( 적어도 우리 서비스는 이렇다 )
- 단일 버전 운영 — npm 패키지처럼 여러 버전이 동시에 사용되지 않는다. 현재 배포된 버전 하나의 이미지만 존재한다.
- 외부 API 계약이 없는 경우 — 내부 서비스라면
1.0.0 → 2.0.0에서 MAJOR 가 올라가는 게 외부 사용자에게 의미가 없다
이런 환경에서는 1.47.3 보다 2026.05.02 가 훨씬 직관적이다. 배포 이력을 뒤져보지 않아도 이 이미지가 언제 빌드된 건지 바로 알 수 있다. 특히 우리는 배포가 잘못되었을때, 이전 버전의 이미지 태그를 찾아서 넣곤 했었는데, 이때 전 버전이 무슨 태그였는지 찾는것도 일이였다.
| AS-IS | TO-BE |
|---|---|
![]() | ![]() |
언제 어떤 걸 써야 할까?
IMPORTANT정답은 없다. 다만 기준을 잡는 데 도움이 되는 질문들이 있다.
SemVer 가 더 적합한 경우:
- 외부에 공개하는 라이브러리, SDK, API
- 여러 버전이 동시에 사용되는 환경 (npm 패키지 등)
- 하위 호환성 여부를 명시적으로 전달해야 하는 경우
CalVer 가 더 적합한 경우:
- 내부 서비스, 웹 애플리케이션
- 지속적으로 배포되는 환경
- Docker 이미지 태깅 전략
- 버전 번호에서 배포 시기를 바로 파악해야 하는 경우
마치며
버저닝 방식마저 고민할 기회가 없었던거 같다. 다들 이렇게 사용하고 이렇게 적용되어져 있었고, 그것에 맞춰서 사용했을 뿐, 이번에 Docker 이미지 태그를 정리하면서 처음으로 진지하게 생각해보게 됐다.
SemVer 가 사실상 표준처럼 자리 잡혀 있어서 “당연히 시멘틱 버저닝이지”라고 무심코 쓰고 있었는데, 맥락에 따라 CalVer가 훨씬 자연스러운 경우도 있다는 걸 알게 됐다.
버저닝 전략 하나에도 “왜 이 방식인가?”라는 스스로에게 질문을 던져보는 게 정말 중요한거 같다.
다른 프로젝트들도 이렇게 하나씩 calandar versioning으로 변경하려고 한다.
레퍼런스

