セマンティックバージョニング

MAJOR.MINOR.PATCH の 3 桁でソフトウェアの互換性を表現するバージョニング規約

開発プラクティスパッケージ管理

セマンティックバージョニングとは

セマンティックバージョニング (SemVer) は、MAJOR.MINOR.PATCH の 3 桁でソフトウェアの互換性を表現するバージョニング規約である。Tom Preston-Werner (GitHub 共同創業者) が策定し、現行仕様は 2.0.0 (2026 年 8 月時点)。狙いは「公開 API に何が起きたか」を番号の増分だけで機械的に読み取れるようにすることで、依存パッケージの自動更新はこの約束を前提に成立している。逆に言えば、番号を守らない配布物が 1 つ混じるだけで自動更新は信頼できなくなる。

バージョン番号の意味

3 つの桁はそれぞれ「利用側のコードに何を要求するか」を表す。

MAJOR.MINOR.PATCH
  2.    1.    3

MAJOR: 後方互換性のない変更 (破壊的変更)
MINOR: 後方互換性のある機能追加
PATCH: 後方互換性のあるバグ修正

具体例

判断の軸は「利用側が自分のコードを書き換えずに済むか」の一点である。

変更内容バージョン変更
バグ修正1.0.0 → 1.0.1
新機能追加 (既存 API は変更なし)1.0.1 → 1.1.0
API の破壊的変更1.1.0 → 2.0.0
セキュリティパッチ2.0.0 → 2.0.1
公開 API の一部を非推奨と表明2.0.1 → 2.1.0

npm でのバージョン指定

npm の範囲指定はこの規約を前提に設計されている。

{
  "dependencies": {
    "express": "^4.18.0",
    "lodash": "~4.17.0",
    "typescript": "5.3.3"
  }
}
記法意味許容範囲
^4.18.0MINOR, PATCH の更新を許可4.18.0 〜 4.x.x
~4.17.0PATCH の更新のみ許可4.17.0 〜 4.17.x
5.3.3完全固定5.3.3 のみ

キャレットが固定するのは「メジャー・マイナー・パッチのうち左端の 0 でない数字」であって、メジャーそのものではない。したがって ^0.2.3 は 0.2.x のパッチだけを許容し、^0.0.3 は 0.0.3 以外のどのバージョンにも一致しない。0.x の依存に ^ を付けても実質は固定で、更新が来ていないのではなく範囲が拾っていない、という読み違いがここで起きる (npm 側の範囲記法も参照)。

破壊的変更の例

破壊的変更は型シグネチャの変更に限らない。投げる例外の種類、引数の既定値、エラー時の戻り方を変えれば、呼び出し側は同じコードのまま壊れる。

// v1: 文字列を返す
function getUser(id: string): string { ... }

// v2: オブジェクトを返す (破壊的変更 → MAJOR を上げる)
function getUser(id: string): User { ... }

プレリリースバージョン

プレリリース版は、パッチ番号の直後にハイフンとドット区切りの識別子を付けて表す。識別子に使えるのは ASCII の英数字とハイフンで、数値識別子に先行ゼロは置けない。

1.0.0-alpha.1  → アルファ版
1.0.0-beta.1   → ベータ版
1.0.0-rc.1     → リリース候補
1.0.0          → 正式リリース

実務で効いてくるのは優先順位の規則である。同じ MAJOR.MINOR.PATCH を持つプレリリース版は、対応する正式版より必ず低い。プレリリース識別子同士は左から順に比較し、数字だけの識別子は数値として、英字やハイフンを含む識別子は ASCII 順の辞書式として比較する。数値識別子は非数値識別子より低く、先行する識別子が全て等しい場合は識別子の数が多い方が高い。仕様が示す順序は次のようになる。

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.2beta.11 より低いのは数値比較だからで、文字列としてソートすると逆順になる。バージョン一覧を素朴に辞書順で並べる処理が「最新」を取り違えるのはこの一点が原因で、比較は必ず SemVer 準拠の実装に任せる。

ビルドメタデータ

プラス記号に続けてドット区切りの識別子を付けると、ビルドメタデータを載せられる。1.0.0+201303131447001.0.0-beta+exp.sha.5114f85 のように、ビルド日時やコミットハッシュを版に添えるのが典型である。

ただし仕様は、ビルドメタデータを優先順位の判定から除外すると定めている。ビルドメタデータだけが違う 2 つの版は同順位であり、1.0.0+build.11.0.0+build.2 のどちらが新しいかを版から決めることはできない。同じビルドを再配布したときの追跡情報としては使えるが、再ビルドごとに番号を上げて別バージョンとして配布する用途には向かない。

0.x.x の特別ルール

仕様は 0.y.z を初期開発用と位置づけ、いつ何が変わってもよい、公開 API は安定とみなすべきでないと明記している。つまり 0.x では MINOR と PATCH の意味づけ自体が保証されない。マイナー更新に破壊的変更が入るのは慣習ではなく、この許容の帰結である。

0.x.x: 初期開発段階
  → いつ何が変わってもよい (公開 API は安定とみなさない)
  → 1.0.0 が公開 API を定義する版

1.0.0 を切るという判断は、機能が揃ったという宣言ではなく「以降は互換性の約束に縛られる」という宣言である。本番で使われ始めた 0.x を長く据え置くと、利用側は破壊的変更を PATCH 相当の気軽さで取り込んでしまう。

Conventional Commits との連携

コミットメッセージの型から増分すべき桁を導けるため、リリース番号の決定と CHANGELOG の生成を自動化できる。

feat: 新機能追加 → MINOR を上げる
fix: バグ修正 → PATCH を上げる
feat!: 破壊的変更 → MAJOR を上げる
BREAKING CHANGE: → MAJOR を上げる

この自動化の正しさは、コミットメッセージの規律に完全に依存する。破壊的変更に !BREAKING CHANGE: を書き忘れると MINOR 更新として公開され、キャレット範囲で依存している利用側はそれを無審査で取り込む。バージョン番号は約束の表明にすぎず、約束を守る仕組みは別に用意する必要がある。

この記事は役に立ちましたか?

関連用語

関連する記事