ULID Generator
Generate lexicographically sortable unique IDs
Нажмите «Сгенерировать» для создания ULID
Что такое ULID?
ULID (Universally Unique Lexicographically Sortable Identifier) — 128-битный формат идентификатора для уникальности и естественной сортируемости. В отличие от UUID v4, ULID встраивает Unix-временную метку в миллисекундах в старшие биты.
ULID кодируется в Base32 по Crockford — компактная 26-символьная строка, безопасная для URL и нечувствительная к регистру.
Спецификация создана Ализайном Фееростой. ULID не является стандартом IETF — это спецификация сообщества (ulid.github.io).
Структура ULID
ULID — 128 бит, два компонента:
| Временная метка | Случайное |
|---|---|
| 01ARZ3NDEK | TSVE4RRFFQ69G5FAV |
| 48 бит — Unix-временная метка в мс. Точность 1 мс. Охватывает до 10889 года. | 80 бит — криптографически защищённые случайные данные. Обновляются для каждого ULID. |
26 символов Crockford Base32: первые 10 — временная метка, последние 16 — случайный компонент.
Алфавит Crockford Base32
Алфавит ULID: 0123456789ABCDEFGHJKMNPQRSTVWXYZ
Четыре символа намеренно исключены:
I— легко спутать с1L— легко спутать с1илиIO— легко спутать с0U— исключена для уменьшения вероятности оскорбительных слов
Crockford Base32 нечувствителен к регистру — строчные <code>i</code>, <code>l</code>, <code>o</code> декодируются как их визуальные аналоги.
ULID против UUID
Сравнение ULID с UUID v4:
| Свойство | ULID | UUID |
|---|---|---|
| Длина | 26 символов | 36 символов (или 32 без дефисов) |
| Биты | 128 бит | 128 бит |
| Лексикографически сортируемый | Да | Нет |
| Временная метка | 48-битный Unix мс | Нет |
| URL-безопасный | Да (Base32) | Да (только hex) |
| Нечувствительный к регистру | Да | Да |
| Стандарт | Спецификация сообщества | RFC 4122 (IETF) |
| Нативная поддержка в браузере | Нет | Да (<code>crypto.randomUUID()</code>) |
Используйте ULID когда нужна временная сортировка, UUID v4 — для максимальной совместимости.
ULID против NanoID
ULID и NanoID — популярные альтернативы UUID с разными целями:
| Свойство | ULID | NanoID |
|---|---|---|
| Длина | 26 символов | 21 символ (по умолчанию) |
| Биты энтропии | 80 бит | 126 бит |
| Временная метка | Да (48-битный мс) | Нет |
| Лексикографически сортируемый | Да | Нет |
| Пользовательский алфавит | Нет (Crockford Base32) | Да (настраиваемый) |
| Нативная поддержка | Нет (нужна библиотека) | Нет (нужна библиотека) |
| Нативная поддержка в браузере | Нет | Да (Web Crypto API) |
Выбирайте ULID для временного порядка, NanoID — для более коротких ID без временной метки.
Поддержка баз данных
ULID хранятся как текст или двоичные данные:
Примеры кода
ULID не стандартизирован нативно. Используйте официальный пакет:
// Using the 'ulid' npm package
import { ulid } from 'ulid'
const id = ulid() // "01ARZ3NDEKTSV4RRFFQ69G5FAV"
const id2 = ulid() // "01ARZ3NDEKXXXXXXXXXXXX..." (same ms, incremented random)
// With a custom timestamp
const id3 = ulid(1469918176385) // deterministic time portion
// Extract the timestamp back out
import { decodeTime } from 'ulid'
decodeTime(id) // → 1469918176385 (Unix ms)# Using python-ulid
from ulid import ULID
uid = ULID()
str(uid) # "01ARZ3NDEKTSV4RRFFQ69G5FAV"
uid.timestamp # 1469918176.385
uid.datetime # datetime(2016, 7, 30, 23, 36, 16, 385000, tzinfo=timezone.utc)
# Parse an existing ULID string
parsed = ULID.from_str("01ARZ3NDEKTSV4RRFFQ69G5FAV")
parsed.timestamp # 1469918176.385-- Store ULIDs as TEXT or CHAR(26)
CREATE TABLE events (
id CHAR(26) PRIMARY KEY DEFAULT gen_ulid(), -- if using a PG extension
name TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- Or pass the ULID from your application layer
INSERT INTO events (id, name, created_at)
VALUES ('01ARZ3NDEKTSV4RRFFQ69G5FAV', 'user.signup', NOW());
-- Range queries are efficient because ULIDs sort chronologically
SELECT * FROM events
WHERE id > '01ARZ3NDEKTSV4RRFFQ69G5FAV'
ORDER BY id
LIMIT 20;// Pure browser / Deno / Node.js implementation (no dependencies)
const CROCKFORD = '0123456789ABCDEFGHJKMNPQRSTVWXYZ'
function encodeTime(ms) {
let result = '', n = BigInt(ms)
for (let i = 9; i >= 0; i--) {
result = CROCKFORD[Number(n & 31n)] + result
n >>= 5n
}
return result
}
function encodeRandom(bytes) {
let n = 0n
for (const b of bytes) n = (n << 8n) | BigInt(b)
let result = ''
for (let i = 15; i >= 0; i--) {
result = CROCKFORD[Number(n & 31n)] + result
n >>= 5n
}
return result
}
function generateULID() {
const randomBytes = new Uint8Array(10)
crypto.getRandomValues(randomBytes)
return encodeTime(Date.now()) + encodeRandom(randomBytes)
}