ULID Generator

Menghasilkan pengenal unik yang dapat diurutkan secara leksikografis

Jumlah

Klik Buat untuk membuat ULID

Apa itu ULID?

ULID (Universally Unique Lexicographically Sortable Identifier) adalah format identifier 128-bit yang dirancang untuk menjadi unik sekaligus dapat diurutkan secara alami.

ULID dikodekan menggunakan alfabet Crockford's Base32, menghasilkan string 26 karakter yang kompak, URL-safe, tidak peka huruf besar/kecil, dan bebas dari karakter yang ambigu secara visual.

Spesifikasi ULID dibuat oleh Alizain Feerasta dan banyak digunakan dalam sistem terdistribusi, event sourcing, dan kunci primer database.

Struktur ULID

ULID selebar 128 bit, dibagi menjadi dua komponen:

TimestampAcak
01ARZ3NDEKTSVE4RRFFQ69G5FAV
48 bit — Timestamp Unix dalam milidetik. Mengkodekan waktu pembuatan dengan presisi 1ms. Mencakup tanggal hingga tahun 10889.80 bit — data acak yang aman secara kriptografi. Diregenerasi segar untuk setiap ULID (kecuali mode monotonik digunakan).

Dikodekan sebagai 26 karakter Crockford Base32: 10 karakter pertama mewakili timestamp, 16 karakter terakhir mewakili komponen acak.

Alfabet Crockford Base32

ULID menggunakan pengkodean Crockford's Base32, yang menggunakan 32 dari 36 karakter alfanumerik. Alfabetnya adalah: 0123456789ABCDEFGHJKMNPQRSTVWXYZ

Mengapa 32 karakter ini?
0123456789ABCDEFGHJKMNPQRSTVWXYZ

Empat karakter sengaja dikecualikan:

  • I dan L dikecualikan — mudah tertukar dengan digit 1
  • O dikecualikan — mudah tertukar dengan digit 0
  • U dikecualikan — menghindari kata yang tidak senonoh secara tidak sengaja dalam ID yang dihasilkan
  • Pengkodean tidak peka huruf besar/kecil01ARZ3NDEKTSV4RRFFQ69G5FAV dan 01arz3ndektsv4rrffq69g5fav adalah ULID yang sama

Crockford Base32 lebih efisien dari heksadesimal (32 simbol vs 16) dan lebih mudah dibaca manusia dari Base64.

ULID vs UUID

ULID dan UUID keduanya mewakili identifier 128-bit, tetapi berbeda secara signifikan dalam pengkodean dan tujuan desain:

PropertiULIDUUID
FormatCrockford Base32Hex bertanda hubung
Panjang26 karakter36 karakter
TimestampUnix ms 48-bitTidak ada (v4) atau ms 48-bit (v7)
Dapat DiurutkanYa — leksikografisTidak (v4) / Ya (v7)
URL-safeYa (hanya alfanumerik)Ya (dengan tanda hubung)
DependensiMemerlukan libraryNative (crypto.randomUUID)
Dukungan DBSimpan sebagai CHAR(26) atau BINARY(16)Tipe kolom UUID native
SpesifikasiSpesifikasi komunitas (ulid.github.io)RFC 4122 / RFC 9562

Jika Anda sudah dalam ekosistem UUID (kolom uuid PostgreSQL, REST API), UUID v7 biasanya lebih cocok daripada ULID. Jika Anda lebih suka pengkodean ramah manusia, ULID adalah pilihan yang sangat baik.

ULID vs nanoid

ULID dan nanoid keduanya menghasilkan identifier pendek yang URL-safe, tetapi memiliki tujuan desain yang berbeda:

PropertiULIDNanoID
TimestampYa — Unix ms 48-bitTidak
Dapat DiurutkanYaTidak
Panjang default26 karakter21 karakter
Entropi80 bit (komponen acak)~126 bit
AlfabetCrockford Base32 (32 karakter)URL-safe Base64 (64 karakter)
Panjang yang dapat dikustomisasiTidakYa (panjang apa pun)
Kasus penggunaanID berurutan waktu, kunci primer DBToken acak, URL pendek, kunci API

Pilih ULID saat Anda membutuhkan pengurutan waktu. Pilih nanoid saat Anda menginginkan entropi maksimal dalam string pendek yang acak.

Menggunakan ULID di Database

ULID dapat disimpan dalam database dengan beberapa cara tergantung pada kebutuhan Anda:

Simpan sebagai CHAR(26)
Pendekatan paling sederhana. Urutan pengurutan leksikografis dipertahankan.
Simpan sebagai BINARY(16)
Dekode ULID ke representasi biner 16-byte untuk penyimpanan yang kompak.
PostgreSQL
Simpan sebagai CHAR(26) atau gunakan tipe bytea untuk penyimpanan biner.
MySQL / MariaDB
Gunakan CHAR(26) CHARACTER SET ascii untuk penyimpanan yang efisien.
SQLite
Simpan sebagai TEXT. Perbandingan teks default SQLite mengurutkan ULID dengan benar.
MongoDB
Simpan sebagai field string. Kemampuan pengurutan leksikografis ULID bekerja secara natural.

Contoh Kode

Pembuatan ULID memerlukan library ulid (tersedia untuk JavaScript, Python, Go, Rust, dan banyak lagi):

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)
}

Pertanyaan yang Sering Diajukan

Apakah ULID unik secara global?
Ya — dengan probabilitas yang sangat tinggi. Komponen acak 80-bit memberikan 2^80 ≈ 1,2 × 10^24 nilai yang mungkin per milidetik per generator.
Apakah ULID sama dengan UUID?
Tidak — ULID dan UUID adalah pengkodean berbeda dari nilai 128-bit.
Bagaimana mode monotonik ULID bekerja?
Dalam mode standar, komponen acak 80-bit dihasilkan baru untuk setiap ULID. Dalam mode monotonik, saat beberapa ULID dihasilkan dalam milidetik yang sama, komponen acak diinkrementasi.
Bisakah saya mendekode ULID untuk mendapatkan timestamp pembuatan?
Ya. 10 karakter Crockford Base32 pertama mengkodekan timestamp Unix milidetik 48-bit.
Apakah ULID merupakan standar resmi?
Tidak. ULID adalah spesifikasi komunitas yang dikelola di ulid.github.io. Ini bukan standar IETF seperti UUID.