1.0.0-rc.1과 1.0.0, 어느 쪽이 높을까: SemVer 프리릴리스 순서와 ^ 범위
1.0.0-rc.1과 1.0.0 중 어느 쪽이 높은지, ^1.2.3이 1.5.0-beta.1을 고르지 않는 이유를 SemVer 2.0.0과 node-semver, Cargo 문서로 정리했습니다.
1.0.0-rc.1과 1.0.0 중 어느 쪽의 우선순위가 높을까요. ^1.2.3으로 의존성을 지정했는데 1.5.0-beta.1은 왜 설치 후보에 들어가지 않을까요.
두 질문의 답은 서로 다른 곳에 있습니다. 버전의 우선순위는 Semantic Versioning 2.0.0 명세가 정합니다. ^1.2.3 같은 범위와 프리릴리스 포함 여부는 그 명세를 사용하는 패키지 도구가 따로 정합니다.
정식 버전은 숫자로 비교한다
SemVer 정식 버전은 X.Y.Z 형식입니다. 각 자리는 음이 아닌 정수이며 앞에 0을 붙이지 않습니다. 우선순위는 메이저, 마이너, 패치를 왼쪽부터 숫자로 비교해 처음 달라지는 자리에서 결정합니다.
따라서 1.10.0은 1.9.0보다 높습니다. 문자열 정렬을 사용하면 이 순서가 뒤집힐 수 있으므로 버전 목록에는 SemVer 비교 함수를 써야 합니다.
하이픈 뒤는 프리릴리스다
패치 번호 뒤에 하이픈과 식별자를 붙이면 프리릴리스 버전이 됩니다.
1.0.0-alpha
1.0.0-beta.2
1.0.0-rc.1
메이저·마이너·패치가 같다면 프리릴리스는 정식 버전보다 낮습니다.
1.0.0-rc.1 < 1.0.0
프리릴리스끼리는 점으로 나눈 식별자를 왼쪽부터 비교합니다. 숫자로만 된 식별자는 숫자로 비교하고, 다른 식별자는 ASCII 순서로 비교합니다. 숫자 식별자는 숫자가 아닌 식별자보다 낮습니다. 앞부분이 모두 같다면 식별자가 더 많은 쪽이 높습니다.
SemVer 명세의 예시는 다음과 같습니다.
1.0.0-alpha
< 1.0.0-alpha.1
< 1.0.0-alpha.beta
< 1.0.0-beta
< 1.0.0-beta.2
< 1.0.0-beta.11
< 1.0.0-rc.1
< 1.0.0
beta.2와 beta.11에서 2와 11은 별도의 숫자 식별자이므로 숫자로 비교됩니다. 반면 rc9와 rc10은 각각 하나의 영숫자 식별자입니다. 문자 순서로는 rc10이 rc9보다 낮습니다. 번호가 두 자리를 넘을 수 있다면 rc.9, rc.10처럼 점으로 분리하는 편이 의도와 잘 맞습니다.
빌드 메타데이터는 우선순위에 영향을 주지 않는다
+ 뒤에는 빌드 메타데이터를 붙일 수 있습니다.
1.0.0+build.1
1.0.0+build.2
SemVer는 우선순위를 계산할 때 빌드 메타데이터를 무시합니다. 위 두 버전은 빌드 표기가 다르지만 우선순위는 같습니다.
^1.2.3이 프리릴리스를 고르지 않는 이유
SemVer 명세에는 ^1.2.3 같은 범위 문법이 없습니다. 이 문법은 도구가 정의합니다.
npm이 사용하는 node-semver에서 ^1.2.3은 다음 범위로 전개됩니다.
>=1.2.3 <2.0.0-0
2.0.0-0은 유효한 2.0.0 프리릴리스 중 우선순위가 가장 낮은 값입니다. 따라서 이 상한은 2.0.0의 프리릴리스도 제외합니다.
하지만 이것만으로 1.5.0-beta.1이 제외되는 이유가 모두 설명되지는 않습니다. 우선순위만 보면 이 버전은 두 경계 사이에 있습니다. node-semver에는 별도의 프리릴리스 규칙이 있습니다. 범위 안에 같은 [major, minor, patch]를 가진 프리릴리스 비교자가 있을 때만 해당 프리릴리스를 기본적으로 포함합니다.
그래서 다음 결과가 나옵니다.
1.5.0-beta.1 satisfies ^1.2.3 → false
1.2.3-beta.4 satisfies ^1.2.3-beta.2 → true
1.2.4-beta.2 satisfies ^1.2.3-beta.2 → false
1.3.0 satisfies ^1.2.3-beta.2 → true
node-semver의 includePrerelease 옵션을 사용하면 기본적인 프리릴리스 제외 정책을 바꿀 수 있습니다. 다만 명시된 상한과 하한까지 무시하는 옵션은 아닙니다.
Cargo의 규칙은 비슷하지만 별도로 확인해야 한다
Cargo도 버전 요구 사항에 프리릴리스를 명시하지 않으면 프리릴리스 버전을 제외합니다. 1.0.0-alpha만 게시된 상태에서 foo = "1.0"을 지정하면 맞는 버전이 없어 오류가 납니다.
foo = "1.0.0-alpha"로 지정하면 같은 1.0.0 계열의 1.0.0-beta나 정식 버전 1.0.0으로 갱신할 수 있습니다. 호환되는 정식 버전인 1.2.0도 대상이 됩니다. 그러나 1.0.1-alpha나 1.0.1-beta로는 갱신하지 않습니다.
프리릴리스를 기본 범위에서 제외하는 것은 SemVer 자체의 규칙이 아닙니다. npm, Cargo 또는 다른 패키지 관리자를 사용할 때는 그 도구의 범위 문서를 따로 확인해야 합니다.
참고한 명세와 문서
- Semantic Versioning 2.0.0
- node-semver README:
Caret Ranges,Prerelease Tags - The Cargo Book — Specifying Dependencies: Pre-releases
링크와 내용은 2026년 10월 1일에 확인했습니다.