nanoid、randomstring、shortid、uuid はいずれも JavaScript 環境で一意な文字列を生成するための npm パッケージですが、目的や設計思想、API、セキュリティ特性が大きく異なります。uuid は RFC 4122 準拠の汎用的な UUID を生成し、nanoid は極小サイズかつ高速な短い ID を目指します。randomstring は柔軟なカスタマイズ可能なランダム文字列生成に特化し、shortid はかつて人気のあった短い非衝突 ID 生成器でしたが、現在は非推奨となっています。これらのパッケージは、データベースの主キー、一時トークン、URL ショートナー、セッション ID など、さまざまなユースケースで使われますが、適切な選択はアプリケーションの要件に大きく依存します。
フロントエンド開発で「一意な文字列」が必要になる場面は多いです。例えば、リストの各アイテムに key を付ける、一時的なセッション ID を生成する、URL ショートナーを作るなど。しかし、Math.random().toString(36) で済ませるのは危険です。衝突リスクやセキュリティの問題があります。
この記事では、代表的な ID 生成ライブラリである nanoid、randomstring、shortid、uuid を、実際の開発観点から深く比較します。それぞれの強み・弱点をコード付きで解説し、あなたのプロジェクトに最適な選択をサポートします。
shortid は公式に非推奨(deprecated)されています。npm ページおよび GitHub リポジトリに明確な警告が記載されており、新しいプロジェクトでの使用は推奨されません。理由は以下の通りです:
Math.random() に依存しており、暗号論的に安全ではない// ❌ shortid — 新規プロジェクトでは絶対に使わないでください
import shortid from 'shortid';
const id = shortid.generate(); // 例: "23aBc"
代わりに、nanoid や uuid を検討してください。以下では shortid を比較対象から外し、残り3つを詳細に見ていきます。
ID 生成で最も重要なのは「予測不可能性」です。特にトークンやセッション ID など、セキュリティに直結する用途では、Math.random() のような擬似乱数ではなく、暗号論的に安全な乱数生成器(CSPRNG) を使う必要があります。
nanoid:デフォルトで安全nanoid は、Node.js では crypto.randomBytes、ブラウザでは crypto.getRandomValues を内部で使用します。つまり、デフォルトで CSPRNG を利用し、安全です。
// ✅ nanoid — 安全で短い ID
import { nanoid } from 'nanoid';
const id = nanoid(); // 例: "V1StGXR8_Z5jdHi6B-myT"
さらに、CSP(Content Security Policy)環境でも動作するよう、globalThis.crypto を直接参照する設計になっています。
uuid:UUID 標準に準拠uuid も同様に、v4(ランダムベース)では CSPRNG を使用します。RFC 4122 標準に準拠しており、業界で広く受け入れられています。
// ✅ uuid — 標準的で安全
import { v4 as uuidv4 } from 'uuid';
const id = uuidv4(); // 例: "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d"
randomstring:安全ではない一方、randomstring は 暗号論的に安全な乱数をサポートしていません。内部で Math.random() を使用しており、予測可能で衝突リスクも高いため、セキュリティ関連の用途には不向きです。
// ⚠️ randomstring — 安全ではない(Math.random() 使用)
import randomstring from 'randomstring';
const token = randomstring.generate(32); // 危険!セッションIDなどに使わないこと
💡 ポイント:セキュリティが関わる用途(認証トークン、パスワードリセットリンクなど)では、
randomstringは絶対に使わないでください。
生成される ID の長さは、ネットワーク転送量や UI 表示にも影響します。
| パッケージ | デフォルト長さ | 文字セット |
|---|---|---|
nanoid | 21 文字 | -._0-9A-Za-z(URL セーフ) |
uuid (v4) | 36 文字 | 0-9a-f-(ハイフン含む) |
randomstring | 指定可能 | カスタマイズ可能(デフォルトは英数字) |
nanoid は非常にコンパクトで、URL や HTTP ヘッダーに埋め込んでも負担が少ないです。uuid は長さが固定で可読性が高いですが、頻繁に送受信するデータではオーバーヘッドになります。
// 長さ比較
nanoid(); // "KTxH1iZQeF3qJxN8yLmPw" (21)
uuidv4(); // "f47ac10b-58cc-4372-a567-0e02b2c3d479" (36)
randomstring.generate(10); // "x9gF2kLmQp" (任意)
randomstring:柔軟なフォーマット制御randomstring の最大の強みは、生成ルールを細かく指定できることです。
// ✅ randomstring — フォーマットを自由に設定
import randomstring from 'randomstring';
// 英数字のみ、10文字
randomstring.generate({ length: 10, charset: 'alphanumeric' });
// 数字のみ
randomstring.generate({ length: 6, charset: 'numeric' });
// 特定の文字セット
randomstring.generate({ length: 8, charset: 'ABCDEF1234567890' });
このような柔軟性は、パスワード生成やテストデータ作成など、ID の一意性よりも「見た目」や「形式」が重要な場面で役立ちます。
nanoid:カスタムアルファベット対応nanoid もカスタム文字セットに対応していますが、API はより低レベルです。
// ✅ nanoid — カスタムアルファベット
import { customAlphabet } from 'nanoid';
const generateId = customAlphabet('1234567890abcdef', 10);
const id = generateId(); // 例: "a3f9b1c8e2"
ただし、これは依然として CSPRNG を使用するため、randomstring よりも安全です。
uuid:フォーマットは固定uuid は標準に従うため、文字セットや長さのカスタマイズはできません。ただし、ハイフンを除去するなど、後処理は可能です。
// uuid — 後処理で短縮
const compactUuid = uuidv4().replace(/-/g, ''); // 32文字
理論的な衝突確率は、ID のエントロピー(情報量)に依存します。
nanoid(21文字、64文字セット):約 126 ビットのエントロピーuuid v4(122ビットのランダム部分):122 ビットのエントロピーrandomstring(デフォルト32文字、62文字セット):約 190 ビットだが、Math.random() の質が低いので実効エントロピーは低い実用上、nanoid と uuid はどちらも大規模システムで十分な安全性を持ちますが、randomstring は衝突リスクが高いため、大量の ID を生成する用途には向いていません。
nanoid:軽量でモダン環境に最適nanoid はバンドルサイズが極めて小さく(1KB未満)、ESM/CJS の両方をサポートしています。Vite や Webpack との相性も抜群です。
// Vite / React での使用例
import { nanoid } from 'nanoid';
function TodoList() {
const [todos, setTodos] = useState([]);
const addTodo = (text) => {
setTodos([...todos, { id: nanoid(), text }]);
};
}
uuid:安定した選択肢uuid もフロントエンドで問題なく動作しますが、nanoid よりも若干重いです。ただし、多くのバックエンドシステムと互換性があるため、フルスタックで統一したい場合に有利です。
randomstring:Node.js 向けの印象が強いrandomstring はブラウザでも動作しますが、ドキュメントや設計が Node.js ファーストであり、フロントエンドでの利用事例は少ないです。
| ユースケース | 推奨パッケージ | 理由 |
|---|---|---|
React/Vue のリスト key 生成 | nanoid | 軽量、安全、短い |
| 認証トークン、セッション ID | nanoid | CSPRNG 使用、安全 |
| バックエンドと UUID を共有したい | uuid | 標準準拠、相互運用性 |
| テストデータやパスワード生成 | randomstring | フォーマット自由(※安全でないことに注意) |
| URL ショートナーの短いコード | nanoid | URL セーフ、衝突確率低 |
| 新規プロジェクトでの shortid 使用 | 禁止 | 非推奨、安全でない |
nanoid か uuid:迷ったら nanoid がフロントエンド向けに最適です。randomstring:ただし、安全でないことを理解した上で、非セキュリティ用途に限定してください。shortid は即座に置き換えを検討:既存コードにあれば、nanoid への移行は簡単です(API が似ているため)。正しい ID 生成ライブラリを選ぶことで、アプリケーションの信頼性とセキュリティを大きく向上させることができます。安易な Math.random() からの脱却を、ぜひこの機会に。
uuid は、業界標準の UUID(バージョン 1~5、および v7/v8)を生成する必要がある場合に最適です。特にバックエンドシステムやデータベースとの互換性が求められる場合や、グローバルな一意性が必須な分散システムで信頼性が高い選択肢です。ただし、生成される文字列は比較的長く(36文字)、フロントエンドでの軽量利用にはオーバーヘッドが大きい場合があります。
nanoid は、バンドルサイズを最小限に抑えつつ、高速かつ安全な短い ID を必要とするフロントエンドプロジェクトに最適です。URL セーフで衝突確率が低く、CSP(Content Security Policy)環境でも動作します。特にモダンなビルドツール(Vite、Webpack など)と相性が良く、軽量さと安全性のバランスが取れた選択肢です。
randomstring は、特定の文字セット(例:英数字のみ、記号なし)、長さ、パターンに基づいて完全にカスタマイズ可能なランダム文字列を生成したい場合に適しています。パスワード生成やテストデータ作成など、ID の一意性よりもフォーマットの柔軟性が重要な場面で有用ですが、暗号論的に安全な乱数生成には対応していません。
shortid は公式に非推奨(deprecated)とされており、新しいプロジェクトでは使用すべきではありません。衝突リスクが高く、暗号論的に安全でない Math.random() に依存しているため、セキュリティ上問題があります。既存コードで使用されている場合は、nanoid または uuid への移行を強く推奨します。
For the creation of RFC9562 (formerly RFC4122) UUIDs
crypto API for random valuesuuid command line utility[!NOTE]
Starting with
uuid@12CommonJS is no longer supported. See implications and motivation for details.
1. Install
npm install uuid
2. Create a UUID
import { v4 as uuidv4 } from 'uuid';
uuidv4(); // ⇨ '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d'
For timestamp UUIDs, namespace UUIDs, and other options read on ...
uuid.NIL | The nil UUID string (all zeros) | New in uuid@8.3 |
uuid.MAX | The max UUID string (all ones) | New in uuid@9.1 |
uuid.parse() | Convert UUID string to array of bytes | New in uuid@8.3 |
uuid.stringify() | Convert array of bytes to UUID string | New in uuid@8.3 |
uuid.v1() | Create a version 1 (timestamp) UUID | |
uuid.v1ToV6() | Create a version 6 UUID from a version 1 UUID | New in uuid@10 |
uuid.v3() | Create a version 3 (namespace w/ MD5) UUID | |
uuid.v4() | Create a version 4 (random) UUID | |
uuid.v5() | Create a version 5 (namespace w/ SHA-1) UUID | |
uuid.v6() | Create a version 6 (timestamp, reordered) UUID | New in uuid@10 |
uuid.v6ToV1() | Create a version 1 UUID from a version 6 UUID | New in uuid@10 |
uuid.v7() | Create a version 7 (Unix Epoch time-based) UUID | New in uuid@10 |
uuid.v8() | "Intentionally left blank" | |
uuid.validate() | Test a string to see if it is a valid UUID | New in uuid@8.3 |
uuid.version() | Detect RFC version of a UUID | New in uuid@8.3 |
The nil UUID string (all zeros).
Example:
import { NIL as NIL_UUID } from 'uuid';
NIL_UUID; // ⇨ '00000000-0000-0000-0000-000000000000'
The max UUID string (all ones).
Example:
import { MAX as MAX_UUID } from 'uuid';
MAX_UUID; // ⇨ 'ffffffff-ffff-ffff-ffff-ffffffffffff'
Convert UUID string to array of bytes
str | A valid UUID String |
| returns | Uint8Array[16] |
| throws | TypeError if str is not a valid UUID |
[!NOTE] Ordering of values in the byte arrays used by
parse()andstringify()follows the left ↠ right order of hex-pairs in UUID strings. As shown in the example below.
Example:
import { parse as uuidParse } from 'uuid';
// Parse a UUID
uuidParse('6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b'); // ⇨
// Uint8Array(16) [
// 110, 192, 189, 127, 17,
// 192, 67, 218, 151, 94,
// 42, 138, 217, 235, 174,
// 11
// ]
Convert array of bytes to UUID string
arr | Array-like collection of 16 values (starting from offset) between 0-255. |
[offset = 0] | Number Starting index in the Array |
| returns | String |
| throws | TypeError if a valid UUID string cannot be generated |
[!NOTE] Ordering of values in the byte arrays used by
parse()andstringify()follows the left ↠ right order of hex-pairs in UUID strings. As shown in the example below.
Example:
import { stringify as uuidStringify } from 'uuid';
const uuidBytes = Uint8Array.of(
0x6e,
0xc0,
0xbd,
0x7f,
0x11,
0xc0,
0x43,
0xda,
0x97,
0x5e,
0x2a,
0x8a,
0xd9,
0xeb,
0xae,
0x0b
);
uuidStringify(uuidBytes); // ⇨ '6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b'
Create an RFC version 1 (timestamp) UUID
[options] | Object with one or more of the following properties: |
[options.node = (random) ] | RFC "node" field as an Array[6] of byte values (per 4.1.6) |
[options.clockseq = (random)] | RFC "clock sequence" as a Number between 0 - 0x3fff |
[options.msecs = (current time)] | RFC "timestamp" field (Number of milliseconds, unix epoch) |
[options.nsecs = 0] | RFC "timestamp" field (Number of nanoseconds to add to msecs, should be 0-10,000) |
[options.random = (random)] | Array of 16 random bytes (0-255) used to generate other fields, above |
[options.rng] | Alternative to options.random, a Function that returns an Array of 16 random bytes (0-255) |
[buffer] | Uint8Array or Uint8Array subtype (e.g. Node.js Buffer). If provided, binary UUID is written into the array, starting at offset |
[offset = 0] | Number Index to start writing UUID bytes in buffer |
| returns | UUID String if no buffer is specified, otherwise returns buffer |
| throws | Error if more than 10M UUIDs/sec are requested |
[!NOTE] The default node id (the last 12 digits in the UUID) is generated once, randomly, on process startup, and then remains unchanged for the duration of the process.
[!NOTE]
options.randomandoptions.rngare only meaningful on the very first call tov1(), where they may be passed to initialize the internalnodeandclockseqfields.
Example:
import { v1 as uuidv1 } from 'uuid';
uuidv1(); // ⇨ '2c5ea4c0-4067-11e9-9b5d-ab8dfbbd4bed'
Example using options:
import { v1 as uuidv1 } from 'uuid';
const options = {
node: Uint8Array.of(0x01, 0x23, 0x45, 0x67, 0x89, 0xab),
clockseq: 0x1234,
msecs: new Date('2011-11-01').getTime(),
nsecs: 5678,
};
uuidv1(options); // ⇨ '710b962e-041c-11e1-9234-0123456789ab'
Convert a UUID from version 1 to version 6
import { v1ToV6 } from 'uuid';
v1ToV6('92f62d9e-22c4-11ef-97e9-325096b39f47'); // ⇨ '1ef22c49-2f62-6d9e-97e9-325096b39f47'
Create an RFC version 3 (namespace w/ MD5) UUID
API is identical to v5(), but uses "v3" instead.
[!IMPORTANT] Per the RFC, "If backward compatibility is not an issue, SHA-1 [Version 5] is preferred."
Create an RFC version 4 (random) UUID
[options] | Object with one or more of the following properties: |
[options.random] | Array of 16 random bytes (0-255) |
[options.rng] | Alternative to options.random, a Function that returns an Array of 16 random bytes (0-255) |
[buffer] | Uint8Array or Uint8Array subtype (e.g. Node.js Buffer). If provided, binary UUID is written into the array, starting at offset |
[offset = 0] | Number Index to start writing UUID bytes in buffer |
| returns | UUID String if no buffer is specified, otherwise returns buffer |
Example:
import { v4 as uuidv4 } from 'uuid';
uuidv4(); // ⇨ '1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed'
Example using predefined random values:
import { v4 as uuidv4 } from 'uuid';
const v4options = {
random: Uint8Array.of(
0x10,
0x91,
0x56,
0xbe,
0xc4,
0xfb,
0xc1,
0xea,
0x71,
0xb4,
0xef,
0xe1,
0x67,
0x1c,
0x58,
0x36
),
};
uuidv4(v4options); // ⇨ '109156be-c4fb-41ea-b1b4-efe1671c5836'
Create an RFC version 5 (namespace w/ SHA-1) UUID
name | String | Array |
namespace | String | Array[16] Namespace UUID |
[buffer] | Uint8Array or Uint8Array subtype (e.g. Node.js Buffer). If provided, binary UUID is written into the array, starting at offset |
[offset = 0] | Number Index to start writing UUID bytes in buffer |
| returns | UUID String if no buffer is specified, otherwise returns buffer |
[!NOTE] The RFC
DNSandURLnamespaces are available asv5.DNSandv5.URL.
Example with custom namespace:
import { v5 as uuidv5 } from 'uuid';
// Define a custom namespace. Readers, create your own using something like
// https://www.uuidgenerator.net/
const MY_NAMESPACE = '1b671a64-40d5-491e-99b0-da01ff1f3341';
uuidv5('Hello, World!', MY_NAMESPACE); // ⇨ '630eb68f-e0fa-5ecc-887a-7c7a62614681'
Example with RFC URL namespace:
import { v5 as uuidv5 } from 'uuid';
uuidv5('https://www.w3.org/', uuidv5.URL); // ⇨ 'c106a26a-21bb-5538-8bf2-57095d1976c1'
Create an RFC version 6 (timestamp, reordered) UUID
This method takes the same arguments as uuid.v1().
import { v6 as uuidv6 } from 'uuid';
uuidv6(); // ⇨ '1e940672-c5ea-64c1-9bdd-2b0d7b3dcb6d'
Example using options:
import { v6 as uuidv6 } from 'uuid';
const options = {
node: [0x01, 0x23, 0x45, 0x67, 0x89, 0xab],
clockseq: 0x1234,
msecs: new Date('2011-11-01').getTime(),
nsecs: 5678,
};
uuidv6(options); // ⇨ '1e1041c7-10b9-662e-9234-0123456789ab'
Convert a UUID from version 6 to version 1
import { v6ToV1 } from 'uuid';
v6ToV1('1ef22c49-2f62-6d9e-97e9-325096b39f47'); // ⇨ '92f62d9e-22c4-11ef-97e9-325096b39f47'
Create an RFC version 7 (random) UUID
[options] | Object with one or more of the following properties: |
[options.msecs = (current time)] | RFC "timestamp" field (Number of milliseconds, unix epoch) |
[options.random = (random)] | Array of 16 random bytes (0-255) used to generate other fields, above |
[options.rng] | Alternative to options.random, a Function that returns an Array of 16 random bytes (0-255) |
[options.seq = (random)] | 32-bit sequence Number between 0 - 0xffffffff. This may be provided to help ensure uniqueness for UUIDs generated within the same millisecond time interval. Default = random value. |
[buffer] | Uint8Array or Uint8Array subtype (e.g. Node.js Buffer). If provided, binary UUID is written into the array, starting at offset |
[offset = 0] | Number Index to start writing UUID bytes in buffer |
| returns | UUID String if no buffer is specified, otherwise returns buffer |
Example:
import { v7 as uuidv7 } from 'uuid';
uuidv7(); // ⇨ '01695553-c90c-745a-b76f-770d7b3dcb6d'
"Intentionally left blank"
[!NOTE] Version 8 (experimental) UUIDs are "for experimental or vendor-specific use cases". The RFC does not define a creation algorithm for them, which is why this package does not offer a
v8()method. Thevalidate()andversion()methods do work with such UUIDs, however.
Test a string to see if it is a valid UUID
str | String to validate |
| returns | true if string is a valid UUID, false otherwise |
Example:
import { validate as uuidValidate } from 'uuid';
uuidValidate('not a UUID'); // ⇨ false
uuidValidate('6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b'); // ⇨ true
Using validate and version together it is possible to do per-version validation, e.g. validate for only v4 UUIds.
import { version as uuidVersion } from 'uuid';
import { validate as uuidValidate } from 'uuid';
function uuidValidateV4(uuid) {
return uuidValidate(uuid) && uuidVersion(uuid) === 4;
}
const v1Uuid = 'd9428888-122b-11e1-b85c-61cd3cbb3210';
const v4Uuid = '109156be-c4fb-41ea-b1b4-efe1671c5836';
uuidValidateV4(v4Uuid); // ⇨ true
uuidValidateV4(v1Uuid); // ⇨ false
Detect RFC version of a UUID
str | A valid UUID String |
| returns | Number The RFC version of the UUID |
| throws | TypeError if str is not a valid UUID |
Example:
import { version as uuidVersion } from 'uuid';
uuidVersion('45637ec4-c85f-11ea-87d0-0242ac130003'); // ⇨ 1
uuidVersion('6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b'); // ⇨ 4
[!NOTE] This method returns
0for theNILUUID, and15for theMAXUUID.
UUIDs can be generated from the command line using uuid.
$ npx uuid
ddeb27fb-d9a0-4624-be4d-4615062daed4
The default is to generate version 4 UUIDS, however the other versions are supported. Type uuid --help for details:
$ npx uuid --help
Usage:
uuid
uuid v1
uuid v3 <name> <namespace uuid>
uuid v4
uuid v5 <name> <namespace uuid>
uuid v7
uuid --help
Note: <namespace uuid> may be "URL" or "DNS" to use the corresponding UUIDs
defined by RFC9562
options Handling for Timestamp UUIDsPrior to uuid@11, it was possible for options state to interfere with the internal state used to ensure uniqueness of timestamp-based UUIDs (the v1(), v6(), and v7() methods). Starting with uuid@11, this issue has been addressed by using the presence of the options argument as a flag to select between two possible behaviors:
options: Internal state is utilized to improve UUID uniqueness.options: Internal state is NOT used and, instead, appropriate defaults are applied as needed.Browsers: uuid builds are tested against the latest version of desktop Chrome, Safari, Firefox, and Edge. Mobile versions of these same browsers are expected to work but aren't currently tested.
Node: uuid builds are tested against node (LTS releases), plus one prior. E.g. At the time of this writing node@20 is the "maintenance" release and node@24 is the "current" release, so uuid supports node@18-node@24.
Typescript: TS versions released within the past two years are supported. source
This error occurs in environments where the standard crypto.getRandomValues() API is not supported. This issue can be resolved by adding an appropriate polyfill:
react-native-get-random-valuesuuid. Since uuid might also appear as a transitive dependency of some other imports it's safest to just import react-native-get-random-values as the very first thing in your entry point:import 'react-native-get-random-values';
import { v4 as uuidv4 } from 'uuid';
Markdown generated from README_js.md by