uuid vs nanoid vs randomstring vs shortid
フロントエンドアプリケーションにおける一意な識別子生成ライブラリの選定
uuidnanoidrandomstringshortid類似パッケージ:

フロントエンドアプリケーションにおける一意な識別子生成ライブラリの選定

nanoidrandomstringshortiduuid はいずれも JavaScript 環境で一意な文字列を生成するための npm パッケージですが、目的や設計思想、API、セキュリティ特性が大きく異なります。uuid は RFC 4122 準拠の汎用的な UUID を生成し、nanoid は極小サイズかつ高速な短い ID を目指します。randomstring は柔軟なカスタマイズ可能なランダム文字列生成に特化し、shortid はかつて人気のあった短い非衝突 ID 生成器でしたが、現在は非推奨となっています。これらのパッケージは、データベースの主キー、一時トークン、URL ショートナー、セッション ID など、さまざまなユースケースで使われますが、適切な選択はアプリケーションの要件に大きく依存します。

npmのダウンロードトレンド

3 年

GitHub Starsランキング

統計詳細

パッケージ
ダウンロード数
Stars
サイズ
Issues
公開日時
ライセンス
uuid105,969,34415,24866.7 kB46ヶ月前MIT
nanoid026,67612.8 kB46日前MIT
randomstring052316.6 kB21年前MIT
shortid05,72421.7 kB161年前MIT

一意な ID 生成ライブラリ徹底比較: nanoid vs randomstring vs shortid vs uuid

フロントエンド開発で「一意な文字列」が必要になる場面は多いです。例えば、リストの各アイテムに key を付ける、一時的なセッション ID を生成する、URL ショートナーを作るなど。しかし、Math.random().toString(36) で済ませるのは危険です。衝突リスクやセキュリティの問題があります。

この記事では、代表的な ID 生成ライブラリである nanoidrandomstringshortiduuid を、実際の開発観点から深く比較します。それぞれの強み・弱点をコード付きで解説し、あなたのプロジェクトに最適な選択をサポートします。

⚠️ まず確認:非推奨パッケージの存在

shortid は公式に非推奨(deprecated)されています。npm ページおよび GitHub リポジトリに明確な警告が記載されており、新しいプロジェクトでの使用は推奨されません。理由は以下の通りです:

  • Math.random() に依存しており、暗号論的に安全ではない
  • 短い文字列ゆえに衝突確率が高く、スケールすると問題が顕在化
  • 開発が停止されており、バグ修正や改善が行われていない
// ❌ shortid — 新規プロジェクトでは絶対に使わないでください
import shortid from 'shortid';
const id = shortid.generate(); // 例: "23aBc"

代わりに、nanoiduuid を検討してください。以下では 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 表示にも影響します。

パッケージデフォルト長さ文字セット
nanoid21 文字-._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() の質が低いので実効エントロピーは低い

実用上、nanoiduuid はどちらも大規模システムで十分な安全性を持ちますが、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軽量、安全、短い
認証トークン、セッション IDnanoidCSPRNG 使用、安全
バックエンドと UUID を共有したいuuid標準準拠、相互運用性
テストデータやパスワード生成randomstringフォーマット自由(※安全でないことに注意)
URL ショートナーの短いコードnanoidURL セーフ、衝突確率低
新規プロジェクトでの shortid 使用禁止非推奨、安全でない

💡 最終アドバイス

  • セキュリティが関わるなら nanoiduuid:迷ったら nanoid がフロントエンド向けに最適です。
  • フォーマットの自由度が必要なら randomstring:ただし、安全でないことを理解した上で、非セキュリティ用途に限定してください。
  • shortid は即座に置き換えを検討:既存コードにあれば、nanoid への移行は簡単です(API が似ているため)。

正しい ID 生成ライブラリを選ぶことで、アプリケーションの信頼性とセキュリティを大きく向上させることができます。安易な Math.random() からの脱却を、ぜひこの機会に。

選び方: uuid vs nanoid vs randomstring vs shortid

  • uuid:

    uuid は、業界標準の UUID(バージョン 1~5、および v7/v8)を生成する必要がある場合に最適です。特にバックエンドシステムやデータベースとの互換性が求められる場合や、グローバルな一意性が必須な分散システムで信頼性が高い選択肢です。ただし、生成される文字列は比較的長く(36文字)、フロントエンドでの軽量利用にはオーバーヘッドが大きい場合があります。

  • nanoid:

    nanoid は、バンドルサイズを最小限に抑えつつ、高速かつ安全な短い ID を必要とするフロントエンドプロジェクトに最適です。URL セーフで衝突確率が低く、CSP(Content Security Policy)環境でも動作します。特にモダンなビルドツール(Vite、Webpack など)と相性が良く、軽量さと安全性のバランスが取れた選択肢です。

  • randomstring:

    randomstring は、特定の文字セット(例:英数字のみ、記号なし)、長さ、パターンに基づいて完全にカスタマイズ可能なランダム文字列を生成したい場合に適しています。パスワード生成やテストデータ作成など、ID の一意性よりもフォーマットの柔軟性が重要な場面で有用ですが、暗号論的に安全な乱数生成には対応していません。

  • shortid:

    shortid は公式に非推奨(deprecated)とされており、新しいプロジェクトでは使用すべきではありません。衝突リスクが高く、暗号論的に安全でない Math.random() に依存しているため、セキュリティ上問題があります。既存コードで使用されている場合は、nanoid または uuid への移行を強く推奨します。

uuid のREADME

uuid CI Browser

For the creation of RFC9562 (formerly RFC4122) UUIDs

[!NOTE]

Starting with uuid@12 CommonJS is no longer supported. See implications and motivation for details.

Quickstart

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 ...

API Summary

uuid.NILThe nil UUID string (all zeros)New in uuid@8.3
uuid.MAXThe max UUID string (all ones)New in uuid@9.1
uuid.parse()Convert UUID string to array of bytesNew in uuid@8.3
uuid.stringify()Convert array of bytes to UUID stringNew in uuid@8.3
uuid.v1()Create a version 1 (timestamp) UUID
uuid.v1ToV6()Create a version 6 UUID from a version 1 UUIDNew 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) UUIDNew in uuid@10
uuid.v6ToV1()Create a version 1 UUID from a version 6 UUIDNew in uuid@10
uuid.v7()Create a version 7 (Unix Epoch time-based) UUIDNew in uuid@10
uuid.v8()"Intentionally left blank"
uuid.validate()Test a string to see if it is a valid UUIDNew in uuid@8.3
uuid.version()Detect RFC version of a UUIDNew in uuid@8.3

API

uuid.NIL

The nil UUID string (all zeros).

Example:

import { NIL as NIL_UUID } from 'uuid';

NIL_UUID; // ⇨ '00000000-0000-0000-0000-000000000000'

uuid.MAX

The max UUID string (all ones).

Example:

import { MAX as MAX_UUID } from 'uuid';

MAX_UUID; // ⇨ 'ffffffff-ffff-ffff-ffff-ffffffffffff'

uuid.parse(str)

Convert UUID string to array of bytes

strA valid UUID String
returnsUint8Array[16]
throwsTypeError if str is not a valid UUID

[!NOTE] Ordering of values in the byte arrays used by parse() and stringify() 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
// ]

uuid.stringify(arr[, offset])

Convert array of bytes to UUID string

arrArray-like collection of 16 values (starting from offset) between 0-255.
[offset = 0]Number Starting index in the Array
returnsString
throwsTypeError if a valid UUID string cannot be generated

[!NOTE] Ordering of values in the byte arrays used by parse() and stringify() 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'

uuid.v1([options[, buffer[, offset]]])

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
returnsUUID String if no buffer is specified, otherwise returns buffer
throwsError 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.random and options.rng are only meaningful on the very first call to v1(), where they may be passed to initialize the internal node and clockseq fields.

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'

uuid.v1ToV6(uuid)

Convert a UUID from version 1 to version 6

import { v1ToV6 } from 'uuid';

v1ToV6('92f62d9e-22c4-11ef-97e9-325096b39f47'); // ⇨ '1ef22c49-2f62-6d9e-97e9-325096b39f47'

uuid.v3(name, namespace[, buffer[, offset]])

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."

uuid.v4([options[, buffer[, offset]]])

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
returnsUUID 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'

uuid.v5(name, namespace[, buffer[, offset]])

Create an RFC version 5 (namespace w/ SHA-1) UUID

nameString | Array
namespaceString | 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
returnsUUID String if no buffer is specified, otherwise returns buffer

[!NOTE] The RFC DNS and URL namespaces are available as v5.DNS and v5.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'

uuid.v6([options[, buffer[, offset]]])

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'

uuid.v6ToV1(uuid)

Convert a UUID from version 6 to version 1

import { v6ToV1 } from 'uuid';

v6ToV1('1ef22c49-2f62-6d9e-97e9-325096b39f47'); // ⇨ '92f62d9e-22c4-11ef-97e9-325096b39f47'

uuid.v7([options[, buffer[, offset]]])

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
returnsUUID String if no buffer is specified, otherwise returns buffer

Example:

import { v7 as uuidv7 } from 'uuid';

uuidv7(); // ⇨ '01695553-c90c-745a-b76f-770d7b3dcb6d'

uuid.v8()

"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. The validate() and version() methods do work with such UUIDs, however.

uuid.validate(str)

Test a string to see if it is a valid UUID

strString to validate
returnstrue 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

uuid.version(str)

Detect RFC version of a UUID

strA valid UUID String
returnsNumber The RFC version of the UUID
throwsTypeError 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 0 for the NIL UUID, and 15 for the MAX UUID.

Command Line

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 UUIDs

Prior 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:

  • Without options: Internal state is utilized to improve UUID uniqueness.
  • With options: Internal state is NOT used and, instead, appropriate defaults are applied as needed.

Support

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

Known issues

"getRandomValues() not supported"

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 / Expo

  1. Install react-native-get-random-values
  2. Import it before uuid. 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