ULID Generator
Menghasilkan pengenal unik yang dapat diurutkan secara leksikografis
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:
| Timestamp | Acak |
|---|---|
| 01ARZ3NDEK | TSVE4RRFFQ69G5FAV |
| 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
Empat karakter sengaja dikecualikan:
IdanLdikecualikan — mudah tertukar dengan digit1Odikecualikan — mudah tertukar dengan digit0Udikecualikan — menghindari kata yang tidak senonoh secara tidak sengaja dalam ID yang dihasilkan- Pengkodean
tidak peka huruf besar/kecil—01ARZ3NDEKTSV4RRFFQ69G5FAVdan01arz3ndektsv4rrffq69g5favadalah 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:
| Properti | ULID | UUID |
|---|---|---|
| Format | Crockford Base32 | Hex bertanda hubung |
| Panjang | 26 karakter | 36 karakter |
| Timestamp | Unix ms 48-bit | Tidak ada (v4) atau ms 48-bit (v7) |
| Dapat Diurutkan | Ya — leksikografis | Tidak (v4) / Ya (v7) |
| URL-safe | Ya (hanya alfanumerik) | Ya (dengan tanda hubung) |
| Dependensi | Memerlukan library | Native (crypto.randomUUID) |
| Dukungan DB | Simpan sebagai CHAR(26) atau BINARY(16) | Tipe kolom UUID native |
| Spesifikasi | Spesifikasi 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:
| Properti | ULID | NanoID |
|---|---|---|
| Timestamp | Ya — Unix ms 48-bit | Tidak |
| Dapat Diurutkan | Ya | Tidak |
| Panjang default | 26 karakter | 21 karakter |
| Entropi | 80 bit (komponen acak) | ~126 bit |
| Alfabet | Crockford Base32 (32 karakter) | URL-safe Base64 (64 karakter) |
| Panjang yang dapat dikustomisasi | Tidak | Ya (panjang apa pun) |
| Kasus penggunaan | ID berurutan waktu, kunci primer DB | Token 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:
Contoh Kode
Pembuatan ULID memerlukan library ulid (tersedia untuk JavaScript, Python, Go, Rust, dan banyak lagi):
// 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)
}