uuid vs nanoid vs shortid vs randomstring
前端唯一 ID 生成器套件比較
uuidnanoidshortidrandomstring類似パッケージ:

前端唯一 ID 生成器套件比較

nanoid、randomstring、shortid 和 uuid 都是用於在 JavaScript 應用程式中生成唯一識別碼(ID)的工具,但各自針對不同使用場景進行優化。nanoid 強調短小、快速且加密安全;randomstring 提供高度可自訂的字串生成(如驗證碼),但預設不安全;shortid 已被官方棄用,不建議用於新專案;uuid 則實作標準化的通用唯一識別碼(UUID),廣泛用於需要跨系統相容性的場合。這些套件在安全性、ID 長度、格式彈性及維護狀態上有顯著差異,開發者需根據實際需求謹慎選擇。

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

3 年

GitHub Starsランキング

統計詳細

パッケージ
ダウンロード数
Stars
サイズ
Issues
公開日時
ライセンス
uuid399,942,44115,34565.7 kB822日前MIT
nanoid360,043,58727,11814.7 kB21ヶ月前MIT
shortid1,271,9995,70921.7 kB162年前MIT
randomstring1,088,62452217 kB21ヶ月前MIT

前端唯一 ID 生成器深度比較:nanoid、randomstring、shortid 與 uuid

在現代前端應用中,我們經常需要產生不重複的識別碼(ID)— 從臨時 UI 元件 key、本地快取索引,到客戶端預先建立的資料實體。nanoid、randomstring、shortid 和 uuid 是四個常見選擇,但它們設計目標、安全性和使用情境大不相同。本文將從實際工程角度深入剖析這些套件的技術細節與取捨。

🔑 核心用途與設計哲學

nanoid 專注於「安全、簡短、快速」的隨機 ID 生成,使用加密安全的亂數來源(Web Crypto API),並針對 bundle size 和執行速度高度優化。適合需要高碰撞抗性且對長度敏感的場景(如 URL 縮網址、前端臨時 ID)。

randomstring 提供極高的客製化彈性,允許指定字元集、長度、甚至排除易混淆字元(如 0/O, l/1)。但預設不使用加密安全亂數,需手動啟用。適合需要特定格式(如密碼、驗證碼)而非純粹唯一 ID 的情境。

shortid 曾是輕量級 ID 生成熱門選擇,但官方已明確標示為棄用(deprecated),建議不要用於新專案。其演算法非加密安全,且存在可預測性問題。

uuid 實作 RFC4122 標準,支援 v1(時間戳 + MAC)、v4(隨機)、v5(命名空間雜湊)等多種版本。v4 是最常用選項,提供強大的唯一性保證,但 ID 長度固定為 36 字元(含連字號),較不適合對長度敏感的場景。

🧪 安全性與碰撞風險

加密安全亂數來源

只有 nanoid 和 uuid (v4) 預設使用加密安全亂數(crypto.getRandomValues() 或 Node.js 的 crypto.randomBytes)。這對防止 ID 被預測至關重要 — 例如用於認證 token 或公開資源識別碼。

randomstring 預設使用 Math.random(),不具備加密安全性。若需安全亂數,必須明確設定 generator: 'crypto'。

shortid 使用非加密安全演算法,且因位數不足(7-14 字元),在高頻率生成下碰撞機率顯著上升。

// nanoid: 預設即安全
import { nanoid } from 'nanoid';
const id = nanoid(); // 例: "V1StGXR8_Z5jdHi6B-myT"

// randomstring: 需手動啟用安全模式
import randomString from 'randomstring';
const unsafe = randomString.generate(10); // 使用 Math.random()
const safe = randomString.generate({
  length: 10,
  generator: 'crypto' // 必須指定
});

// uuid: v4 預設安全
import { v4 as uuidv4 } from 'uuid';
const id = uuidv4(); // 例: "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d"

// shortid: 不安全且已棄用
import shortid from 'shortid';
const id = shortid.generate(); // 例: "SJWvrXhPf" — 避免使用!

📏 ID 長度與格式控制

套件預設長度可自訂長度可自訂字元集固定格式
nanoid21✅✅(透過 alphabet)❌
randomstring32✅✅(完整控制)❌
shortid7-14(動態)⚠️(有限)❌❌
uuid36(含 -)❌❌✅(RFC4122)

nanoid 在預設 21 字元下,碰撞機率遠低於 UUID v4(因使用更大字元集:A-Za-z0-9_-)。若需更短 ID,可安全縮減長度:

import { customAlphabet } from 'nanoid';
const nanoidShort = customAlphabet('1234567890abcdef', 10);
const id = nanoidShort(); // 例: "a3f9c8e2b1"

randomstring 提供最細緻的格式控制,適合生成人類可讀 ID:

// 生成不含易混淆字元的 8 位驗證碼
const code = randomString.generate({
  length: 8,
  charset: 'alphanumeric',
  capitalization: 'uppercase',
  exclude: '0O1l'
}); // 例: "A2B4C6D8"

uuid 的格式嚴格遵循標準,若需移除連字號,需手動處理:

const compact = uuidv4().replace(/-/g, ''); // 32 字元無分隔符

⚡ 效能與 Bundle Size

雖然指令禁止提及具體數字,但從設計上:

  • nanoid 為最小化 bundle size 設計,核心邏輯極簡,適合對體積敏感的前端專案。
  • uuid 因支援多版本(v1/v3/v4/v5),整體體積較大,但可 tree-shaking 僅引入 v4。
  • randomstring 因功能豐富(多種生成器、字元集邏輯),體積相對較大。
  • shortid 雖小,但因已棄用且不安全,不應考慮。

🚫 shortid 已正式棄用

根據 npm 頁面 與 GitHub 倉庫,shortid 自 2018 年起不再維護,作者明確建議遷移至 nanoid。其主要問題包括:

  1. 非加密安全:使用可預測的 PRNG
  2. 碰撞風險高:短 ID + 非均勻分佈
  3. 無 TypeScript 支援

重要提醒:任何新專案都應避免使用 shortid。既有專案應規劃遷移。

🛠️ 實際使用場景建議

場景 1:前端臨時元件 Key(如動態表單欄位)

  • 推薦:nanoid
  • 原因:短小、快速、安全,且無需標準相容性
// React 中生成唯一 key
{fields.map(field => (
  <Input key={field.id || nanoid()} />
))}

場景 2:公開資源識別碼(如分享連結)

  • 推薦:nanoid(自訂字母表)或 uuid v4
  • 原因:需高碰撞抗性與不可預測性
// 生成 12 位 URL 安全 ID
const shareId = customAlphabet('abcdefghijklmnopqrstuvwxyz0123456789', 12)();

場景 3:人類可讀驗證碼或密碼

  • 推薦:randomstring
  • 原因:需排除易混淆字元、控制大小寫
// 生成 6 位數字驗證碼
const otp = randomString.generate({
  length: 6,
  charset: 'numeric'
});

場景 4:需與後端 UUID 相容的 ID

  • 推薦:uuid v4
  • 原因:確保前後端 ID 格式一致
// 客戶端預先建立實體
const newPost = {
  id: uuidv4(),
  title: 'Hello'
};

📌 總結:如何選擇?

需求最佳選擇
最短、最快、安全的隨機 IDnanoid
完全自訂格式(如驗證碼)randomstring(記得啟用 crypto)
標準相容 UUIDuuid v4
任何新專案絕對不要用 shortid

記住:若你的 ID 會暴露給外部(如 URL、API 回應),務必使用加密安全亂數。nanoid 和 uuid v4 是前端最穩健的選擇;randomstring 僅在需要特殊格式時使用,且要小心設定安全選項。

選び方: uuid vs nanoid vs shortid vs randomstring

  • uuid:

    選擇 uuid 若你需要符合 RFC4122 標準的通用唯一識別碼(特別是 v4 隨機版本),以確保與後端系統或其他服務的相容性。UUID v4 提供強大的唯一性保證和加密安全性,但 ID 長度固定(36 字元含連字號),不適合對長度敏感的場景。

  • nanoid:

    選擇 nanoid 若你需要生成短小(預設 21 字元)、加密安全且高效能的隨機 ID。它特別適合前端臨時識別碼、URL 縮網址或任何對長度敏感又需高碰撞抗性的場景。其設計極簡,bundle size 小,且預設使用 Web Crypto API 保證安全性。

  • shortid:

    不要選擇 shortid — 此套件已由作者正式標示為棄用(deprecated),且存在安全性與碰撞風險問題。官方文件明確建議遷移至 nanoid。任何新專案都應避免使用,既有專案應規劃替換方案。

  • randomstring:

    選擇 randomstring 若你需要高度自訂格式的字串(如排除易混淆字元的驗證碼、特定字元集的密碼),而非純粹的唯一 ID。注意:預設使用 Math.random() 不具備加密安全性,必須明確設定 generator: 'crypto' 才能用於敏感場景。

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(); // ⇨ 'b18794e8-5d0d-417c-b361-ba38e78411b4'

For timestamp UUIDs, namespace UUIDs, and other options read on ...

API Summary

uuid.NILThe nil UUID string (all zeros)
uuid.MAXThe max UUID string (all ones)
uuid.parse()Convert UUID string to array of bytes
uuid.stringify()Convert array of bytes to UUID string
uuid.v1()Generate a version 1 (timestamp) UUID
uuid.v1ToV6()Convert a version 1 UUID to version 6
uuid.v3()Generate a version 3 (namespace w/ MD5) UUID
uuid.v4()Generate a version 4 (random) UUID
uuid.v5()Generate a version 5 (namespace w/ SHA-1) UUID
uuid.v6()Generate a version 6 (timestamp, reordered) UUID
uuid.v6ToV1()Convert a version 6 UUID to version 1
uuid.v7()Generate a version 7 (Unix Epoch time-based) UUID
uuid.v8()"Intentionally left blank"
uuid.validate()Test a string to see if it is a valid UUID
uuid.version()Detect RFC version of a UUID

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

Example:

import { v1 as uuidv1 } from 'uuid';

uuidv1(); // ⇨ '57fd0000-c7d3-11ef-841d-514d2167fc5b'

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(); // ⇨ 'b18794e8-5d0d-417c-b361-ba38e78411b4'

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(); // ⇨ '1efc7d35-7fd0-6000-841d-504d2167fc5b'

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(); // ⇨ '01941f29-7c00-73e4-a310-744d2167fc5b'

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@20-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';

Generated from README_js.md by runmd