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 бит, два компонента:

Временная меткаСлучайное
01ARZ3NDEKTSVE4RRFFQ69G5FAV
48 бит — Unix-временная метка в мс. Точность 1 мс. Охватывает до 10889 года.80 бит — криптографически защищённые случайные данные. Обновляются для каждого ULID.

26 символов Crockford Base32: первые 10 — временная метка, последние 16 — случайный компонент.

Алфавит Crockford Base32

Алфавит ULID: 0123456789ABCDEFGHJKMNPQRSTVWXYZ

Почему именно эти 32 символа?
0123456789ABCDEFGHJKMNPQRSTVWXYZ

Четыре символа намеренно исключены:

  • I — легко спутать с 1
  • L — легко спутать с 1 или I
  • O — легко спутать с 0
  • U — исключена для уменьшения вероятности оскорбительных слов

Crockford Base32 нечувствителен к регистру — строчные <code>i</code>, <code>l</code>, <code>o</code> декодируются как их визуальные аналоги.

ULID против UUID

Сравнение ULID с UUID v4:

СвойствоULIDUUID
Длина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 с разными целями:

СвойствоULIDNanoID
Длина26 символов21 символ (по умолчанию)
Биты энтропии80 бит126 бит
Временная меткаДа (48-битный мс)Нет
Лексикографически сортируемыйДаНет
Пользовательский алфавитНет (Crockford Base32)Да (настраиваемый)
Нативная поддержкаНет (нужна библиотека)Нет (нужна библиотека)
Нативная поддержка в браузереНетДа (Web Crypto API)

Выбирайте ULID для временного порядка, NanoID — для более коротких ID без временной метки.

Поддержка баз данных

ULID хранятся как текст или двоичные данные:

Первичные ключи баз данных
ULID обеспечивают сортировку для индексов с компактным представлением.
Событийный источник и журналы событий
Хронологический порядок событий без отдельного поля временной метки.
Распределённые системы
Несколько узлов генерируют ULID независимо без координации.
URL и API
ULID безопасны для URL без кодирования.
Сортируемые очереди сообщений
Ключи очереди, гарантирующие обработку по времени.
Экспорт данных и отчётность
Записи с ULID можно лексикографически сортировать по полю ID.

Примеры кода

ULID не стандартизирован нативно. Используйте официальный пакет:

JavaScript (ulid npm)
// 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)
Python (python-ulid)
# 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
PostgreSQL
-- 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;
JavaScript (pure — no dependencies)
// 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)
}

Часто задаваемые вопросы

Является ли ULID безопасным для URL?
Да. Символы Crockford Base32 (<code>0-9</code> и <code>A-Z</code> без <code>I</code>, <code>L</code>, <code>O</code>, <code>U</code>) безопасны для URL без процентного кодирования.
Могут ли два ULID совпасть?
В стандартном режиме крайне маловероятно: 80 бит случайности = 2<sup>80</sup> возможных значений в каждую миллисекунду.
Что такое монотонный режим ULID?
При генерации нескольких ULID в одну миллисекунду случайный компонент следующего инкрементируется на 1. Гарантирует строгий монотонный порядок.
Совместим ли ULID с UUID?
Двоично — да (128 бит). Строково — нет (Base32 vs hex с дефисами). Не смешивайте без явного преобразования.
Каково максимальное значение временной метки ULID?
48-битная временная метка позволяет представлять даты до 10889 года нашей эры.