🦁

ID について - UUID の代替

に公開

概要

アプリケーションを作成中、データに割り振る ID に何を使うべきか迷いました。UUID は一般的でよさそうだったのですが、もっと短いものも欲しかったのです。

今回は、まず、UUID に代わり、短く一意な ID を生成してくれる、JavaScript のライブラリを調査しました。特定した各ライブラリについて、以下の観点で比較分析します。

  • 生成される ID の長さと使用文字セット(URLセーフか否か)
  • 衝突確率とユニーク性の保証
  • 生成パフォーマンス
  • 時系列でのソート可能性
  • JavaScript での基本的な実装コード例

次に、既存の UUID を可逆的に短くエンコードする一般的な手法を調査し、その手法を実装した JavaScript ライブラリを特定しました。

最後に、短い ID を生成する新しい方法と、既存の UUID を短縮する方法の 2 つのアプローチについて、それぞれの利点、欠点、および適したユースケースを比較しまとめました。

エグゼクティブサマリ

本レポートは、JavaScript 環境における標準 UUIDv4 の代替・短縮手法について分析したものである。UUIDv4 は、36 文字という冗長さによる URL 非効率性や、ランダムな性質が引き起こすデータベースのインデックス断片化(書き込み性能低下)といった課題を抱えている。

調査結果は、これらの課題に対し、二つの主要な戦略を提示している。

  1. 新規IDフォーマットの採用(戦略的転換)
    • NanoID: URL セーフな 21 文字の短いランダム ID である。暗号論的に安全な乱数生成器を使用し、予測不可能性が求められる公開 API キーや URL スラッグに最適である。ただし、時系列ソートはできない。
    • ULID / KSUID: 時間ベースでソート可能な ID(26〜27 文字)である。データベースのプライマリキーとして使用することで、インデックスの断片化を防ぎ、書き込み性能を大幅に向上させる。特にulidはベンチマークで最速クラスの性能を示した。
  2. 既存UUIDの可逆的圧縮(戦術的解決)
    • 既存の 36 文字の UUID を、Base64url、Base62、Base58 などの高基数エンコーディングに変換する手法である。
    • これにより、データ自体は変更せず、URL などで使用する文字列表現のみを約 22 文字に短縮できる。これはあくまでエンコーディングであり、セキュリティ(暗号化)は提供しない点に留意が必要である。

最終的な結論として、最適な戦略は、システムの状況によって異なることが判明した。

  • 新規(グリーンフィールド)プロジェクト
    データ層のパフォーマンス最適化のため、内部プライマリキーにはULIDを、公開IDにはNanoIDを採用する戦略を推奨する。

  • 既存(レガシー)システム
    データベース(データ層)の高コストな変更を避け、プレゼンテーション層(URL など)でのみ既存 UUID を Base58/62/64url で圧縮・エンコードする戦術を推奨する。

1. 短くて一意な ID の生成戦略

標準的な UUIDv4 は、そのランダム性からデータベースのパフォーマンス(インデックス断片化)に問題があり、また URL での利用には長すぎるといった課題を抱えている。この問題を解決するため、NanoID(短く安全なランダムID)、ULID(ソート可能なID)、KSUID(高エントロピーなソート可能 ID)といった代替技術が存在する。本セクションでは、これらのアーキテクチャ、実装、パフォーマンスを比較分析する。

1.1 UUID の限界と代替案の必要性

標準的な UUIDv4 は、36 文字(ハイフン込)という長さが URL で扱うには冗長である。さらに深刻な問題として、そのランダムな性質が B-tree インデックスを持つデータベースにおいてインデックスの断片化を引き起こし、書き込みパフォーマンスを著しく低下させる。また、ID 自体に時間情報を含まないため、時系列でのソートが不可能である。

これらの課題に対応するため、現代の ID 生成には二つの主要なアプローチが存在する。一つは NanoID に代表される「予測不可能性」を重視するアプローチであり、もう一つは ULID や KSUID に代表される「ソート可能性(データベースパフォーマンス)」を重視するアプローチである。

1.2 NanoID: コンパクトで安全なランダム性

NanoID は、「小さく、安全で、URL フレンドリー」という設計思想に基づいている。暗号論的に安全な乱数生成器(CSPRNG)を使用し、UUIDv4 に匹敵する衝突耐性を持ちながら、デフォルトで URL セーフな 21 文字というコンパクトさを実現している。

import { nanoid } from 'nanoid';
const id = nanoid(); // => "V1StGXR8_Z5jdHi6B-myT"

1.3 ULID: 辞書式ソートが可能

ULID は、「辞書式ソート可能」であることを最大の特徴とする。ID は 26 文字の文字列で、前半 10 文字がミリ秒精度のタイムスタンプ、後半 16 文字がランダム部(計 128 ビット)で構成される。

この構造により、ID を文字列としてソートするだけで時系列順に並ぶため、データベースのプライマリキーとして使用した場合、インデックスの断片化を防ぎ、書き込みパフォーマンスを劇的に向上させる。エンコーディングには可読性の高い Crockford's Base32 が使用される。

import { ulid } from "ulid";
const id = ulid(); // => "01ARZ3NDEKTSV4RRFFQ69G5FAV"

1.4 KSUID: ソートが可能で高エントロピー

KSUID も ULID と同様にソート可能だが、より高いランダム性を持つ。27 文字の Base62 エンコードで、32 ビットのタイムスタンプ(秒精度)と 128 ビットのランダムペイロード(計 160 ビット)から構成される。

const KSUID = require('ksuid');
const ksuidFromSync = KSUID.randomSync();
const id = ksuidFromSync.string; // => "1xJnDtfrgJucdg1AH3WJ3L1aHsV"

1.5 比較分析

以下の表は、現代的 ID スキームの機能比較マトリクスである。

機能 UUIDv4 NanoID (default) ULID KSUID
総ビット数 128 126 128 160
ランダムビット数 122 126 80 128
タイムスタンプビット数 0 0 48 32
時間精度 なし なし ミリ秒
ソート可能性 不可 不可 可能 可能
エンコード後長 36(ハイフン込) 21 26 27
文字セット 16進数 Base64url Crockford's Base32 Base62
URLセーフ 不可 (ハイフン)
衝突リスク 無視可能 無視可能 無視可能 無視可能

以下の表は、JavaScript における ID ジェネレータのパフォーマンスベンチマークである。

ライブラリ (実装) 操作回数/秒 相対速度 (最速比)
ulid (monotonic) 約 12,389,000 最速
uuid (v4) 約 8,870,000 28% 低速
nanoid 約 5,300,000 57% 低速
ksuid (汎用) 約 532,000 95.7% 低速

2. UUIDv4 の可逆的圧縮手法

既存の UUIDv4(36 文字)は、データ形式を変更せずに、より短い文字列表現に可逆的に変換できる。これは、128 ビットのデータを 16 進数(Base16)から Base64url、Base62、Base58 といった高基数のエンコーディングに変換することで実現される。この変換により、一般的に 22 文字の URL セーフな文字列が得られる。

2.1 基数変換による圧縮の原理

UUID を短縮する中心的な概念は、基数変換である。標準的な UUID の文字列表現(9b1deb...)は、128 ビットの整数を 16 進数(Base16)で表現したものである。同じ 128 ビットの整数を、より多くの文字を使用する高い基数(例えば Base58、Base62、Base64)で表現することにより、結果として得られる文字列は短くなる。

2.2 エンコーディングとライブラリ

以下に代表的なエンコーディングスキームを示す。

  • Base64url
    Node.js の Buffer でネイティブサポートされており、パフォーマンスが高い。標準 Base64 の+/を、URL セーフな-_に置き換えたものである。
  • Base62
    英数字(0-9a-zA-Z)のみを使用するため、記号を含まないクリーンな見た目が特徴である。
  • Base58
    ビットコインなどで採用されており、視覚的に混同しやすい文字(0, O, I, l)を除外しているため、人間による読み上げや手書きに適している。

以下の表は、UUID エンコーディングスキームの比較である。

スキーム 結果の長さ 文字セット 主な利点 一般的なライブラリ
Base64url 22 A-Za-z0-9-\_ Node.js Buffer でのネイティブサポート、最も広いエコシステム b64id, ネイティブ Buffer
Base62 22 A-Za-z0-9 最もクリーンな外観、記号なし、ダブルクリック選択が容易 uuid62
Base58 22 0OIl を除く英数字 人間の可読性と転記に最適化、視覚的な曖昧さを回避 @nakanoaas/uuid58, uuid-base58

3. 戦略的選定ガイド

最適な ID は、単一の「最良」の ID を求めるのではなく、システムの特性(新規開発か既存システムか)と ID の用途(DB の主キーか公開 ID か)に基づいて戦略的に選定する必要がある。

3.1 ID 生成アプローチの選定に寄与するシステム条件

  • UUID 圧縮(エンコーディング)
    これはプレゼンテーション層における戦術である。主に UUID をネイティブ型で格納している既存システムが対象となる。データモデルという高コストな変更を避けつつ、URL や API レスポンスといったユーザー向けの表示のみを短くする場合に最適である。
  • 新規 ID 採用(ULID/NanoID)
    これはデータ層における戦略的転換である。データベースのパフォーマンスやデータのソート性といった、システムの根幹に関わる問題を解決する。

3.2 最終的な意思決定はどのように行うべきか

最終的な意思決定は、以下の 3 つの問いによって導かれるべきである。

  1. プロジェクトの性質
    新規(グリーンフィールド)プロジェクトか、既存(レガシー)システムか?
  2. IDの用途
    データベースのプライマリキーか、公開される識別子か?
  3. 技術的要件
    時系列での厳密なソートは必要か?

この分析に基づき、システムのアーキテクチャ要求に応じて最適な ID 戦略を選定することが、スケーラビリティ、パフォーマンス、セキュリティを確保する鍵となる。

謝辞

本レポートの作成において、調査には Gemini 2.5 Pro の Deep Research を使用し、要約および草稿の作成に Gemini 2.5 Pro を使用しました。生成内容はすべて精査し、確認しています。

参考文献

  1. Short ID Generation in JavaScript - Tom Spencer, 10月 18, 2025にアクセス、 https://www.tomspencer.dev/blog/2014/11/16/short-id-generation-in-javascript/
  2. What is Nano ID & its difference from UUID as unique identifiers ..., 10月 18, 2025にアクセス、 https://blog.openapihub.com/en-us/what-is-nano-id-its-difference-from-uuid-as-unique-identifiers/
  3. Representing a UUID as a Base62 Hash ID for short, pretty URLs | by Alex Hunt - Medium, 10月 18, 2025にアクセス、 https://medium.com/@huntie/representing-a-uuid-as-a-base-62-hash-id-for-short-pretty-urls-c30e66bf35f9
  4. b64id - npm, 10月 18, 2025にアクセス、 https://www.npmjs.com/package/b64id
  5. UUID vs CUID vs NanoID: Choosing the Right ID Generator for Your Application - Wisp CMS, 10月 18, 2025にアクセス、 https://www.wisp.blog/blog/uuid-vs-cuid-vs-nanoid-choosing-the-right-id-generator-for-your-application
  6. KSUID vs. KUUID: Smarter Unique IDs for Modern Systems | by ..., 10月 18, 2025にアクセス、 https://medium.com/@priyanka.tewatia77/ksuid-vs-kuuid-smarter-unique-ids-for-modern-systems-37b07a1cab74
  7. UUID/ULID vs Nanoids - Laracasts, 10月 18, 2025にアクセス、 https://laracasts.com/discuss/channels/laravel/uuidulid-vs-nanoids
  8. Which Unique Identifier Is Right For You? | Om Jogani - GitHub Pages, 10月 18, 2025にアクセス、 https://omjogani.github.io/blogs/posts/which-id-right-for-you/
  9. ULID vs UUID: Sortable Random ID Generators for JavaScript | by ..., 10月 18, 2025にアクセス、 https://blog.bitsrc.io/ulid-vs-uuid-sortable-random-id-generators-for-javascript-183400ef862c
  10. Understanding UUID v4, UUID v7, Snowflake ID, and Nano ID, GUID, ULID, KSUID — In Simple Terms | by Dinesh Arney | Medium, 10月 18, 2025にアクセス、 https://medium.com/@dinesharney/understanding-uuid-v4-uuid-v7-snowflake-id-and-nano-id-in-simple-terms-c50acf185b00
  11. UUID, ULID, NanoIDs and Snowflake IDs , What's the difference? - Hewi's Blog, 10月 18, 2025にアクセス、 https://hewi.blog/uuid-ulid-nanoids-and-snowflake-ids-whats-the-difference
  12. ulid/javascript: Universally Unique Lexicographically ... - GitHub, 10月 18, 2025にアクセス、 https://github.com/ulid/javascript
  13. After a lot of time spent investigating the different kind of (U)UIDs, I've come... - Hacker News, 10月 18, 2025にアクセス、 https://news.ycombinator.com/item?id=25593165
  14. Out of my scope, but why are UUIDs even discussed? ULIDs ~~(and i think Nanoids?... | Hacker News, 10月 18, 2025にアクセス、 https://news.ycombinator.com/item?id=36433268
  15. ai/nanoid: A tiny (124 bytes), secure, URL-friendly, unique ... - GitHub, 10月 18, 2025にアクセス、 https://github.com/ai/nanoid
  16. antiflasher/nanoid-1: A tiny (162 bytes), secure, URL-friendly, unique string ID generator for JavaScript. - GitHub, 10月 18, 2025にアクセス、 https://github.com/antiflasher/nanoid-1
  17. nanoid - NPM, 10月 18, 2025にアクセス、 https://www.npmjs.com/package/nanoid
  18. extrawurst/ulid: Universally Unique Lexicographically Sortable Identifier - GitHub, 10月 18, 2025にアクセス、 https://github.com/extrawurst/ulid
  19. @std/ulid - JSR, 10月 18, 2025にアクセス、 https://jsr.io/@std/ulid
  20. A curated list of awesome Unique IDs - GitHub, 10月 18, 2025にアクセス、 https://github.com/grantcarthew/awesome-unique-id
  21. segmentio/ksuid: K-Sortable Globally Unique IDs - GitHub, 10月 18, 2025にアクセス、 https://github.com/segmentio/ksuid
  22. uuid vs nanoid vs shortid vs cuid vs ksuid vs ulidx | Unique ID Generation Libraries Comparison - NPM Compare, 10月 18, 2025にアクセス、 https://npm-compare.com/uuid,nanoid,shortid,ksuid,cuid,ulidx
  23. Comparison to ULID · Issue #8 · segmentio/ksuid - GitHub, 10月 18, 2025にアクセス、 https://github.com/segmentio/ksuid/issues/8
  24. Likelihood of collision using most significant bits of a UUID in Java - Stack Overflow, 10月 18, 2025にアクセス、 https://stackoverflow.com/questions/325443/likelihood-of-collision-using-most-significant-bits-of-a-uuid-in-java
  25. owpz/ksuid - GitHub, 10月 18, 2025にアクセス、 https://github.com/owpz/ksuid
  26. Globally Unique Identifier a fair comparison | by Olivier Refalo ..., 10月 18, 2025にアクセス、 https://medium.com/@orefalo_66733/globally-unique-identifier-a-fair-comparison-12b114c78ead
  27. shanehughes3/uuid62: Base-62 UUID generator - GitHub, 10月 18, 2025にアクセス、 https://github.com/shanehughes3/uuid62
  28. nakanoaas/uuid58 - NPM, 10月 18, 2025にアクセス、 https://npmjs.com/package/@nakanoaas/uuid58
  29. cbschuld/uuid-base58: Generate a RFC4122 compliant v4 UUID and return it encoded in base-58. This is great for creating unique IDs which only consume 22 characters of storage. Also provides base-58 encoding and decoding. - GitHub, 10月 18, 2025にアクセス、 https://github.com/cbschuld/uuid-base58
  30. uuid-base64 CDN by jsDelivr - A CDN for npm and GitHub, 10月 18, 2025にアクセス、 https://www.jsdelivr.com/package/npm/uuid-base64
  31. How to generate base62 UUIDs in node.js? - Stack Overflow, 10月 18, 2025にアクセス、 https://stackoverflow.com/questions/30468292/how-to-generate-base62-uuids-in-node-js
  32. Base64 - Glossary | MDN - Mozilla, 10月 18, 2025にアクセス、 https://developer.mozilla.org/en-US/docs/Glossary/Base64
  33. For years already I've been using UUID v4 (generated from a good random source), 10月 18, 2025にアクセス、 https://news.ycombinator.com/item?id=15226459
  34. How To Encode and Decode Strings with Base64 in JavaScript - DigitalOcean, 10月 18, 2025にアクセス、 https://www.digitalocean.com/community/tutorials/how-to-encode-and-decode-strings-with-base64-in-javascript
  35. base-62 - npm search, 10月 18, 2025にアクセス、 https://www.npmjs.com/search?q=base-62
  36. A Deep Dive into Base58 with JavaScript in Browser - MojoAuth, 10月 18, 2025にアクセス、 https://mojoauth.com/binary-encoding-decoding/base58-with-javascript-in-browser/
  37. Base58 String Encoder - Online - Browserling Web Developer Tools, 10月 18, 2025にアクセス、 https://www.browserling.com/tools/base58-encode
  38. @nakanoaas/uuid58 - npm, 10月 18, 2025にアクセス、 https://www.npmjs.com/package/@nakanoaas/uuid58
  39. ksuid - npm, 10月 18, 2025にアクセス、 https://www.npmjs.com/package/ksuid

Discussion