Идентификаторы объектов в программных системах выполняют роль стабильных ключей, позволяющих однозначно ссылаться на сущности в базе данных, API, кеше и распределённых системах. Наиболее распространённым стандартом долгое время оставался UUID (Universally Unique Identifier), определённый в RFC 4122.
UUID представляет собой 128-битное число, обычно отображаемое в виде строки:
550e8400-e29b-41d4-a716-446655440000
Основные версии UUID:
На практике чаще всего используется UUID v4 благодаря простоте и отсутствию утечки информации о системе генерации.
Несмотря на распространённость, UUID имеет ряд особенностей:
Эти ограничения привели к появлению более современных идентификаторов.
ULID (Universally Unique Lexicographically Sortable Identifier) представляет собой альтернативу UUID, разработанную для решения проблемы сортировки и читаемости.
Формат ULID:
01ARZ3NDEKTSV4RRFFQ69G5FAV
Структура:
Ключевые свойства:
ULID особенно полезен в системах, где важна сортировка по времени без
дополнительного поля createdAt.
Пример генерации в Jav * aScript:
import { ulid } from "ulid";
const id = ulid();
CUID (Collision-resistant Unique IDentifier) разрабатывался с прицелом на устойчивость к коллизиям в распределённых системах и высокую скорость генерации.
Пример CUID:
cjld2cyuq0000t3rmniod1foy
Особенности:
Существуют версии:
Пример:
import { createId } from "@paralleldrive/cuid2";
const id = createId();
NanoID представляет собой лёгкую альтернативу UUID и CUID, ориентированную на минимальный размер и высокую производительность.
Пример:
V1StGXR8_Z5jdHi6B-myT
Особенности:
Пример генерации:
import { nanoid } from "nanoid";
const id = nanoid();
NanoID часто применяется в frontend-приложениях, URL-идентификаторах и системах, где важен компактный формат.
| Тип | Сортировка по времени | Длина | Читаемость | Основной сценарий |
|---|---|---|---|---|
| UUID | Нет (v4) / частично | 36 | низкая | универсальные системы |
| ULID | Да | 26 | средняя | базы данных, event-log |
| CUID | частично | ~25 | средняя | распределённые системы |
| NanoID | нет | 21+ | высокая | frontend, URL |
Выбор идентификатора зависит от требований к индексации, скорости генерации и необходимости временной сортировки.
В системах с типизацией на уровне схем часто требуется строгое описание формата идентификаторов. Библиотека Zod позволяет описывать такие правила декларативно.
Базовая валидация UUID:
import { z } from "zod";
const UUIDSchema = z.string().uuid();
Проверка ULID через регулярное выражение:
const ULIDSchema = z.string().regex(/^[0-9A-HJKMNP-TV-Z]{26}$/);
CUID2:
const CUID2Schema = z.string().regex(/^[a-z0-9]{24,}$/);
NanoID (по умолчанию 21 символ):
const NanoIDSchema = z.string().regex(/^[A-Za-z0-9_-]{21}$/);
В сложных системах один тип сущности может использовать разные форматы идентификаторов. Zod позволяет комбинировать схемы через объединения:
const IDSchema = z.union([
z.string().uuid(),
z.string().regex(/^[0-9A-HJKMNP-TV-Z]{26}$/), // ULID
z.string().regex(/^[a-z0-9]{24,}$/) // CUID2
]);
Это полезно при интеграции с внешними сервисами или миграции между системами идентификаторов.
Zod позволяет не только валидировать, но и преобразовывать данные:
const NormalizedID = z.string().transform((val) => val.trim().toLowerCase());
Для ULID можно дополнительно проверять временную корректность:
const ULIDWithTime = z.string().refine((val) => {
const timestamp = val.slice(0, 10);
return !Number.isNaN(parseInt(timestamp, 32));
});
В архитектурах с единым источником правды часто требуется связать генерацию и валидацию идентификаторов.
import { nanoid } from "nanoid";
const UserSchema = z.object({
id: z.string().default(() => nanoid()),
email: z.string().email()
});
Такой подход позволяет централизовать правила формирования данных и избежать рассинхронизации между клиентом и сервером.
Разные типы идентификаторов по-разному влияют на производительность:
В реляционных БД часто применяют текстовые или бинарные представления UUID/ULID, в зависимости от движка.
Типичные проблемы:
Zod позволяет частично компенсировать эти ошибки, фиксируя формат данных на границе системы, но не решает архитектурные проблемы выбора идентификатора.