nanoid、shortid、uniqid 和 uuid 都是用于在 JavaScript 项目中生成唯一标识符(ID)的工具库。它们解决了在分布式系统、数据库主键、会话令牌或临时文件名中创建不重复字符串的需求。uuid 是行业标准,生成符合 RFC4122 规范的通用唯一识别码;nanoid 是现代化的替代方案,专注于更小的体积和 URL 安全性;shortid 曾经很流行但目前已停止维护;uniqid 则提供基于时间戳的简单生成逻辑。开发者需要根据安全性要求、ID 格式规范以及包体积限制来选择合适方案。
在构建前端或全栈应用时,生成唯一 ID 是一个常见需求。无论是作为列表项的 key、数据库主键,还是临时上传令牌,选择一个合适的 ID 生成库都至关重要。nanoid、shortid、uniqid 和 uuid 是生态中最常见的四个选项,但它们的设计目标和适用场景截然不同。本文将从安全性、标准合规性、维护状态和实际代码表现进行深度对比。
生成 ID 的核心风险在于“碰撞”(即生成了两个相同的 ID)。不同的库使用不同的算法来避免这种情况。
nanoid 使用加密强度的随机数生成器。这意味着它的 ID 是不可预测的,非常适合用于会话令牌或公开的资源 ID。
// nanoid: 加密安全,碰撞概率极低
import { nanoid } from 'nanoid';
const id = nanoid();
// 输出示例: "V1StGXR8_Z5jdHi6B-myT"
uuid (通常指 v4 版本) 也使用随机数生成,符合 RFC4122 标准。它的碰撞概率同样极低,但生成的字符串更长。
// uuid: 标准随机 UUID (v4)
import { v4 as uuidv4 } from 'uuid';
const id = uuidv4();
// 输出示例: "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d"
uniqid 主要基于当前时间戳(微秒级)加上少量随机数。它不是加密安全的。如果在高并发环境下同一微秒内生成多个 ID,碰撞风险会显著增加。
// uniqid: 基于时间戳,非加密安全
import uniqid from 'uniqid';
const id = uniqid();
// 输出示例: "k9g5z8p1m2n3o4p5"
shortid 曾经使用类似的随机算法,但由于其算法实现在高并发下存在已知的碰撞问题,且不再维护,安全性已无法保证。
// shortid: [已弃用] 曾经流行,现不建议使用
import shortid from 'shortid';
const id = shortid.generate();
// 输出示例: "P1Zt3n"
ID 的长度直接影响数据库存储成本和 URL 的美观度。此外,某些字符(如 - 或 _)在 URL 中可能需要转义。
nanoid 默认生成 21 个字符的字符串,仅包含 URL 安全字符(A-Z, a-z, 0-9, _, -)。这意味着你可以直接把它放在 URL 中而无需编码。
// nanoid: 短小且 URL 安全
import { nanoid } from 'nanoid';
console.log(nanoid()); // 21 字符,无特殊符号
uuid 生成 36 个字符的字符串,包含连字符。虽然连字符在 URL 中通常是安全的,但长度是 nanoid 的近两倍。
// uuid: 标准格式,较长
import { v4 as uuidv4 } from 'uuid';
console.log(uuidv4()); // 36 字符,包含 4 个连字符
uniqid 生成的长度不固定,通常较短,但字符集可能包含非 URL 友好字符,具体取决于版本和参数。
// uniqid: 长度可变
import uniqid from 'uniqid';
console.log(uniqid()); // 约 13-20 字符
shortid 生成的 ID 非常短(通常 7-14 字符),这是它曾经流行的主要原因,但这是以牺牲部分安全性为代价的。
// shortid: [已弃用] 极短
import shortid from 'shortid';
console.log(shortid.generate()); // 7-14 字符
在前端项目中,每一个字节都很重要。引入一个庞大的库只为生成一个 ID 是不划算的。
nanoid 设计之初就为了极致轻量。它的代码非常精简,对打包后的体积影响几乎可以忽略不计。
// nanoid: 极小体积,高性能
// 安装:npm install nanoid
import { nanoid } from 'nanoid';
// 适合对体积敏感的前端项目
uuid 功能非常全面(支持 v1 到 v5 各种版本),因此代码量相对较大。如果你只需要 v4 随机 ID,引入整个库可能显得有些沉重(尽管可以通过 tree-shaking 优化)。
// uuid: 功能全,体积相对较大
// 安装:npm install uuid
import { v4 as uuidv4 } from 'uuid';
// 适合需要多种 UUID 版本的后端或全栈项目
uniqid 体积也很小,逻辑简单,但功能单一。
// uniqid: 轻量,逻辑简单
// 安装:npm install uniqid
import uniqid from 'uniqid';
// 适合简单的临时 ID 需求
shortid 体积虽小,但考虑到其已弃用状态,体积优势已不再具有吸引力。
// shortid: [已弃用] 体积小但风险高
// 不建议在新项目中使用
选择一个库不仅仅是看功能,还要看它是否有人维护。使用无人维护的库会给项目带来长期的技术债务。
| 包名 | 维护状态 | 建议 |
|---|---|---|
nanoid | 🟢 活跃维护 | 强烈推荐。现代 Web 开发的首选。 |
uuid | 🟢 活跃维护 | 推荐。需要标准 UUID 时的唯一选择。 |
uniqid | 🟡 维护较少 | 可用。仅限非关键业务场景。 |
shortid | 🔴 已弃用 | 禁止使用。请迁移至 nanoid。 |
shortid 的 GitHub 仓库和 npm 页面已明确标记为 Deprecated(弃用)。作者明确指出该库存在碰撞问题,并建议所有用户迁移到 nanoid。在新项目中继续使用 shortid 是不负责任的技术决策。
你需要为动态列表生成 key,或者在 Firestore/Redis 中存储文档。
nanoid// 推荐做法
import { nanoid } from 'nanoid';
const todos = [{ id: nanoid(), text: 'Learn JS' }];
你的后端数据库(如 PostgreSQL)强制要求 UUID 格式,或者需要与其他微服务互通 ID。
uuid// 推荐做法
import { v4 as uuidv4 } from 'uuid';
const transactionId = uuidv4();
你只需要一个临时的 ID 来标记一次点击或一个临时文件,即使碰撞了也没大碍。
uniqid// 可用做法
import uniqid from 'uniqid';
const tempLogId = uniqid();
你正在维护一个使用了 shortid 的旧项目。
nanoid// 迁移前 (不推荐)
// import shortid from 'shortid';
// 迁移后 (推荐)
import { nanoid } from 'nanoid';
这四个库代表了 ID 生成方案的演进历程。shortid 是过去的流行选择,但已退出历史舞台;uniqid 是简单的工具,适合边缘场景;uuid 是稳健的行业标准,适合严肃的后端集成;而 nanoid 则是为现代 Web 开发量身定做的最佳平衡点。
决策清单:
nanoid。它更快、更短、更安全。uuid。shortid。uniqid 也可以。最终建议:对于绝大多数前端架构决策,nanoid 是目前的最佳实践。它在安全性、体积和开发者体验之间取得了最好的平衡。
如果你的项目是现代化的 Web 应用,且需要安全、URL 友好且体积极小的 ID 生成方案,请首选 nanoid。它在保证加密安全性的同时,生成的字符串比 UUID 更短,非常适合前端场景和 NoSQL 数据库主键。
不要在新项目中使用 shortid。该库已正式弃用,维护者明确建议迁移到 nanoid。继续使用它会带来潜在的安全风险和缺乏后续支持的隐患。
当你需要生成简单的、非安全敏感的临时 ID(例如日志追踪 ID 或临时缓存键),且希望依赖极少时,可以选择 uniqid。但请注意它基于时间戳,碰撞概率高于加密随机方案。
如果你的系统需要严格遵循 RFC4122 标准,或者需要与后端系统、数据库(如 PostgreSQL 的 UUID 类型)进行深度集成,请选择 uuid。它是行业通用标准,兼容性最好,但体积相对较大。
English | 日本語 | Русский | 简体中文 | Bahasa Indonesia | 한국어 | العربية
A tiny, secure, URL-friendly, unique string ID generator for JavaScript.
“An amazing level of senseless perfectionism, which is simply impossible not to respect.”
crypto.randomUUID().A-Za-z0-9_-).
So ID size was reduced from 36 to 21 symbols.import { nanoid } from "nanoid";
model.id = nanoid(); //=> "V1StGXR8_Z5jdHi6B-myT"
Nano ID is built by Evil Martians, an American design and engineering consultancy for developer tools, AI, and cybersecurity startups.
Read full docs here.