ID について - UUID の代替
概要
アプリケーションを作成中、データに割り振る ID に何を使うべきか迷いました。UUID は一般的でよさそうだったのですが、もっと短いものも欲しかったのです。
今回は、まず、UUID に代わり、短く一意な ID を生成してくれる、JavaScript のライブラリを調査しました。特定した各ライブラリについて、以下の観点で比較分析します。
- 生成される ID の長さと使用文字セット(URLセーフか否か)
- 衝突確率とユニーク性の保証
- 生成パフォーマンス
- 時系列でのソート可能性
- JavaScript での基本的な実装コード例
次に、既存の UUID を可逆的に短くエンコードする一般的な手法を調査し、その手法を実装した JavaScript ライブラリを特定しました。
最後に、短い ID を生成する新しい方法と、既存の UUID を短縮する方法の 2 つのアプローチについて、それぞれの利点、欠点、および適したユースケースを比較しまとめました。
エグゼクティブサマリ
本レポートは、JavaScript 環境における標準 UUIDv4 の代替・短縮手法について分析したものである。UUIDv4 は、36 文字という冗長さによる URL 非効率性や、ランダムな性質が引き起こすデータベースのインデックス断片化(書き込み性能低下)といった課題を抱えている。
調査結果は、これらの課題に対し、二つの主要な戦略を提示している。
-
新規IDフォーマットの採用(戦略的転換)
- NanoID: URL セーフな 21 文字の短いランダム ID である。暗号論的に安全な乱数生成器を使用し、予測不可能性が求められる公開 API キーや URL スラッグに最適である。ただし、時系列ソートはできない。
-
ULID / KSUID: 時間ベースでソート可能な ID(26〜27 文字)である。データベースのプライマリキーとして使用することで、インデックスの断片化を防ぎ、書き込み性能を大幅に向上させる。特に
ulidはベンチマークで最速クラスの性能を示した。
-
既存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 つの問いによって導かれるべきである。
-
プロジェクトの性質
新規(グリーンフィールド)プロジェクトか、既存(レガシー)システムか? -
IDの用途
データベースのプライマリキーか、公開される識別子か? -
技術的要件
時系列での厳密なソートは必要か?
この分析に基づき、システムのアーキテクチャ要求に応じて最適な ID 戦略を選定することが、スケーラビリティ、パフォーマンス、セキュリティを確保する鍵となる。
謝辞
本レポートの作成において、調査には Gemini 2.5 Pro の Deep Research を使用し、要約および草稿の作成に Gemini 2.5 Pro を使用しました。生成内容はすべて精査し、確認しています。
参考文献
- Short ID Generation in JavaScript - Tom Spencer, 10月 18, 2025にアクセス、 https://www.tomspencer.dev/blog/2014/11/16/short-id-generation-in-javascript/
- 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/
- 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
- b64id - npm, 10月 18, 2025にアクセス、 https://www.npmjs.com/package/b64id
- 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
- 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
- UUID/ULID vs Nanoids - Laracasts, 10月 18, 2025にアクセス、 https://laracasts.com/discuss/channels/laravel/uuidulid-vs-nanoids
- 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/
- 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
- 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
- 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
- ulid/javascript: Universally Unique Lexicographically ... - GitHub, 10月 18, 2025にアクセス、 https://github.com/ulid/javascript
- 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
- 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
- ai/nanoid: A tiny (124 bytes), secure, URL-friendly, unique ... - GitHub, 10月 18, 2025にアクセス、 https://github.com/ai/nanoid
- 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
- nanoid - NPM, 10月 18, 2025にアクセス、 https://www.npmjs.com/package/nanoid
- extrawurst/ulid: Universally Unique Lexicographically Sortable Identifier - GitHub, 10月 18, 2025にアクセス、 https://github.com/extrawurst/ulid
- @std/ulid - JSR, 10月 18, 2025にアクセス、 https://jsr.io/@std/ulid
- A curated list of awesome Unique IDs - GitHub, 10月 18, 2025にアクセス、 https://github.com/grantcarthew/awesome-unique-id
- segmentio/ksuid: K-Sortable Globally Unique IDs - GitHub, 10月 18, 2025にアクセス、 https://github.com/segmentio/ksuid
- 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
- Comparison to ULID · Issue #8 · segmentio/ksuid - GitHub, 10月 18, 2025にアクセス、 https://github.com/segmentio/ksuid/issues/8
- 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
- owpz/ksuid - GitHub, 10月 18, 2025にアクセス、 https://github.com/owpz/ksuid
- Globally Unique Identifier a fair comparison | by Olivier Refalo ..., 10月 18, 2025にアクセス、 https://medium.com/@orefalo_66733/globally-unique-identifier-a-fair-comparison-12b114c78ead
- shanehughes3/uuid62: Base-62 UUID generator - GitHub, 10月 18, 2025にアクセス、 https://github.com/shanehughes3/uuid62
- nakanoaas/uuid58 - NPM, 10月 18, 2025にアクセス、 https://npmjs.com/package/@nakanoaas/uuid58
- 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
- uuid-base64 CDN by jsDelivr - A CDN for npm and GitHub, 10月 18, 2025にアクセス、 https://www.jsdelivr.com/package/npm/uuid-base64
- 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
- Base64 - Glossary | MDN - Mozilla, 10月 18, 2025にアクセス、 https://developer.mozilla.org/en-US/docs/Glossary/Base64
- 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
- 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
- base-62 - npm search, 10月 18, 2025にアクセス、 https://www.npmjs.com/search?q=base-62
- A Deep Dive into Base58 with JavaScript in Browser - MojoAuth, 10月 18, 2025にアクセス、 https://mojoauth.com/binary-encoding-decoding/base58-with-javascript-in-browser/
- Base58 String Encoder - Online - Browserling Web Developer Tools, 10月 18, 2025にアクセス、 https://www.browserling.com/tools/base58-encode
- @nakanoaas/uuid58 - npm, 10月 18, 2025にアクセス、 https://www.npmjs.com/package/@nakanoaas/uuid58
- ksuid - npm, 10月 18, 2025にアクセス、 https://www.npmjs.com/package/ksuid
Discussion