メインコンテンツへ移動

UUIDとNanoIDの違い

どちらも、中央の管理なしに一意であり続ける識別子を生成します。UUIDが標準です。36文字、RFC 9562、すべてのランタイムとデータベースに組み込み。NanoIDはコンパクトな代替で――21文字のURL安全な文字が、同等のエントロピーを運びます。キーとインフラには既定でUUIDを使い、IDがURLに現れるときにNanoIDに手を伸ばしましょう。

端末内で処理

UUIDとNanoIDの違いとは

すべての分散システムには、互いに尋ね合わずとも2台のマシンが同じ瞬間に生成できる識別子が必要です。UUIDは1980年代にこれを解決し、RFC 4122として標準化され、2024年にRFC 9562へ改訂されました。NanoIDは2017年に、より短い文字列を追い求める最小限のライブラリとして登場しました。どちらも同じ数学――たっぷりのランダムビット――によって衝突せず、どちらも調整サーバーを必要としません。

UUIDは128ビットを36文字として表現したものです。8-4-4-4-12のパターンに並ぶ32桁の16進数字のうち、6桁がバージョンとバリアントのマーカーに使われ、バージョン4は122のランダムビットを運びます。既定のNanoIDはA-Za-z0-9_-から引いた21文字――6ビットを表す64種の記号で126のランダムビット、crypto.getRandomValuesによるものです。形状は違っても、衝突確率の天井は一つです。

本当の違いは運用面です。各形状を誰が生成・検証できるか、IDがデータベースのインデックス内でどう振る舞うか、URLの中でどう見えるか、そして選択をどれだけ簡単に覆せるか――以下ですべて測定します。実際の出力を比較できるよう、随所にローカルのジェネレーターをリンクしてあります。

両方の形状を実際の出力で見たいなら、UUIDジェネレーターが完全にブラウザ内で動作します――crypto.getRandomValuesによるもので、ネットワーク呼び出しはなく、ログにも何も残りません。

各バージョンが何をエンコードするかの全容は、UUIDバージョンガイドが実例つきでv1からv8まで順にたどります。

解剖:各IDの中身

UUIDは自分自身のメタデータをエンコードします。ビット48〜51にバージョンが入ります――1は時刻+MAC、4はランダム、7は時刻順のランダム――さらに2ビットがバリアントを固定します。v4は常にランダムに見えます。v7は読めるタイムスタンプで始まります。最初の48ビットがUnixエポックからのミリ秒であり、同じ日に生成されたUUIDは接頭辞を共有するからです。

NanoIDはメタデータを運びません。各文字はアルファベットからの独立した抽出で、crypto.getRandomValuesの上にマスキングと棄却サンプリングを使って選ばれるため、すべての記号が一様に等しく出ます。この純粋さゆえに、フォーマットは柔軟です――アルファベットや長さを変え、アルゴリズムは保てます――そしてNanoIDがいつ作られたかを何も明かさないのもこのためです。

項目UUIDNanoID
規定する仕様RFC 9562(2024年、旧RFC 4122)ライブラリの慣習(nanoid)――RFCなし
既定のサイズ36文字、128ビット21文字、126ビット
アルファベット0-9a-fと4つのハイフンA-Za-z0-9_-(64記号)
乱数の源CSPRNG。crypto.randomUUID()マスキング付きcrypto.getRandomValues
埋め込まれたタイムスタンプv1とv7はあり。v4はなしなし――設計上不透明
実用エントロピー122ビット(v4)。v7はランダム74ビット21文字で126ビット

衝突の数学:なぜどちらも衝突しないのか

誕生日の限界によれば、nビットのランダム識別子は2^(n/2)回の生成付近で衝突確率50%に達します。UUID v4ではおよそ2^61――約230京個のID――で、初めて1つの重複の確率が半分に届きます。NanoIDの126ビットはこのバーをわずかに先へ押します。実務では、どちらも「起こり得ない」システムです。出会う重複があればそれはコードのバグであって、エントロピーの出来事ではありません。

この等価性こそ、サイズ論争が思ったより重要でない理由です。21文字のNanoIDはv4 UUIDより安全なわけではありません――少ないバイト数で同じ保証です。選択の率直な理由は運用上の適合――保存、URL、ツール――であって、衝突リスクではありません。

データベース:インデックス局所性の問題

ランダムなキーをB-treeインデックスに挿入すると、行はどのページにも着地し得ます。ページをランダムな順序で途中まで埋めれば、挿入のたびにページ分割、余分な書き込み、冷えたキャッシュのリスクを負います。これがUUID v4とNanoIDの両方が払う断片化の税です――NanoIDも含まれます。同じようにランダムだからです。書き込みが多い規模でインデックス化された主キーでは、既定のままでインデックスに優しいのはどちらでもありません。

UUID v7は標準の中に組み込まれた修正です。先頭の48ビットがミリ秒のタイムスタンプなので、新しいキーはほぼ常にインデックスの右端に並びます。NanoIDにはこれができません。時刻の要素がなく、並べ替える材料がないからです。インデックス化された列での本当の選択は、v7かそれ以外かです。

  • v4とNanoIDは挿入をツリー全体に散らします――規模が大きくなるとページ分割とキャッシュミスが起こります。
  • Postgresのuuid型は生の16バイトを保存します。36文字のテキストキーなら37バイト以上になります。
  • NanoIDのテキスト面の優位――36文字に対する21文字――は、アルファベットが文書化され続けている間だけ保たれます。

URL、アルファベット、そして長さのダイヤル

NanoIDのアルファベットは構造上URL安全です。A-Za-z0-9_-はURLのどこでもパーセントエンコーディングを必要としないため、IDはパスセグメント、クエリ値、スラッグのどれにも、エスケープゼロでなれます。UUIDも技術的にはURL安全です――16進数字とハイフンはエンコードを必要としない――しかし36文字はリンクに見える文字列としてはかなり長いものです。

カスタムアルファベットはNanoIDの最も実用的な機能です。数字だけのコード、小文字だけの短縮リンク――64記号を差し替え、アルゴリズムは保ちます。エントロピーは長さ×アルファベットサイズのlog2という規則を守ってください。8文字の小文字NanoIDは約38ビットで、1時間用のコードなら十分ですが、主キーとしては無謀です。UUIDにこうしたダイヤルはありません。フォーマットは128ビットに固定されています。

どちらをどの場面で選ぶか

IDがインフラに住むならUUIDを選びましょう。データベースの主キー(v7)、チームやベンダー間の交換、第三者が検証しなければならないもの、組み込みが依存関係に勝るあらゆる場所です。標準そのものが製品です――すべての言語、ORM、データベースがすでに扱えます。

IDがユーザーの目に見えるならNanoIDを選びましょう。短いURL、招待リンク、ファイル名、Cookieの値、ログ内のリクエストIDです。指針はきれいに反転します――URLの中でUUIDの幅と戦い続けているなら、そのリンクはNanoIDを求めています。データベースがネイティブにキーを提供できるバックエンドでNanoIDを再実装しようとしているなら、その列はv7 UUIDを求めています。

よくある質問

サーバーに何も送信せずに、ここでUUIDやNanoIDを生成できますか?

はい。ジェネレーターはブラウザ自身のcrypto.getRandomValuesを使ってタブ内で動作し、リクエストはページから出ません――サイトのContent-Security-Policyが外向きの呼び出しをブロックします。生成中にDevToolsのネットワークパネルを開けば、沈黙し続けるのを確かめられます。乱数はブラウザ経由でOSから来るため、品質はサーバー側の生成に匹敵します。

NanoIDはUUID v4と同じくらい衝突に対して安全ですか?

生のビット数ではわずかに上回ります。126対v4の122です。衝突確率50%の地点は2^61回の生成を少し越えたあたり(v4では約230京個のID)にあり、現実的な規模をはるかに超えています。この差が意味を持つようになるのは、NanoIDの長さやアルファベットを縮めたときだけです。

NanoIDをデータベースの主キーとして使うべきですか?

使えます――しかし21文字のテキストキーはv4と同じだけランダムなので、書き込みの多いテーブルでは同じB-treeの断片化を受け継ぎます。挿入が熱いなら、時刻順のUUID v7がインデックスに優しい選択です。NanoIDが買うのは短い文字列であって、インデックス局所性ではありません。

NanoIDはUUIDのような標準ですか?

いいえ。UUIDはRFC 9562で、すべての言語、Postgresのuuid型、crypto.randomUUID()にネイティブサポートがあります。NanoIDはライブラリの慣習です。数分で再実装できるほど小さい一方、すべての生成者と消費者がアルファベットと長さで合意しなければならず、適合を検証するものは何もありません。その合意こそ、15文字の節約の代金です。

v1よりUUID v7が推奨されるのはなぜですか?

v1のnodeフィールドはマシンのMACアドレスを運ぶため、ハードウェアの同一性が漏れ、システムをまたいでIDが結び付きます。さらに100ナノ秒のグレゴリオ暦タイムスタンプは、Unix時間のツールに対して並べ替えが不格好です。v7はその両方を48ビットのUnixミリ秒+ランダムビットに置き換えます。時刻でソート可能、プライバシーに中立、同じRFCです。新しい設計はv7かv4で始めましょう。

衝突が問題になるのは、NanoIDがどのくらい短くなったときですか?

エントロピーは文字数×アルファベットサイズのlog2で、誕生日の限界では指数を半分にします。既定の21文字は126ビットです。12文字は72ビットで、コインの表裏が分かれるまで約2^36回――ユーザーごとなら十分ですが、グローバルなテーブルには薄いです。8文字はおよそ48ビット。短命のコード向けで、主キーには決して使いません。

ここで引用した規格はどこで読めますか?

  • RFC 9562 — 汎用一意識別子(UUID)
  • RFC 4122 — UUID(汎用一意識別子)のURN名前空間 (RFC 9562により廃止)