Baru mengenal UUID? Mulai dengan panduan Apa Itu UUID? Panduan Lengkap kami untuk dasar-dasar format UUID, versi, dan kasus penggunaan.
UUID v4 vs v7 vs ULID vs Snowflake: Memilih ID yang Tepat untuk Database Anda di 2026
Memilih skema ID yang salah bisa merugikan Anda. Primary key UUID v4 acak pada tabel 100 juta baris menyebabkan hingga 10x lebih banyak page split pada index dibanding ID sekuensial. Snowflake ID memerlukan registri worker terpusat yang menjadi single point of failure. ULID terlihat seperti jalan tengah yang sempurna — sampai UUID v7 hadir sebagai standar IETF.
Artikel ini membahas perbedaan performa, contoh kode, dan kapan masing-masing skema ID tepat digunakan.
Pohon Keputusan Cepat
| Kebutuhan Anda | Pilihan Terbaik | Alasan |
|---|---|---|
| Primary key database (proyek baru) | UUID v7 | Terurut waktu, tipe kolom uuid standar, performa index terbaik |
| ID unik serbaguna (tanpa perlu pengurutan) | UUID v4 | Dukungan universal, tanpa konfigurasi, 122 bit keacakan |
| ID deterministik dari input yang diketahui | UUID v5 | Namespace + name yang sama selalu menghasilkan UUID yang sama |
| Sistem terdistribusi throughput tinggi (>100K ID/detik/node) | Snowflake ID | Integer 64-bit, monotonik dalam satu worker, penyimpanan native BIGINT |
| Token URL-safe pendek atau ID sisi client | NanoID | 21 karakter, alfabet URL-safe, panjang yang dapat disesuaikan |
| Sistem legacy yang sudah menggunakan ULID | ULID | Pertahankan — secara fungsional setara dengan UUID v7, migrasi tidak sebanding |
Penjelasan Mendalam Versi UUID
UUID v1 — Waktu + Alamat MAC (Deprecated)
UUID v1 mengenkode timestamp 60-bit dan alamat MAC 48-bit mesin. Ini adalah “sortable UUID” asli tapi memiliki dua kelemahan fatal: membocorkan identitas hardware dan menggunakan epoch timestamp non-standar (15 Oktober 1582). RFC 9562 secara resmi mendeprecate v1 demi v6/v7. Jangan gunakan v1 di proyek baru.
UUID v4 — Keacakan Murni
UUID v4 mengisi 122 dari 128 bit-nya dengan data acak yang aman secara kriptografis. Ini adalah versi yang paling banyak digunakan — sederhana, privat, dan didukung secara universal.
Kelebihan:
- Tanpa konfigurasi, tidak perlu koordinasi
- Sepenuhnya anonim — tidak ada timestamp atau info hardware yang bocor
- Didukung oleh setiap database, bahasa, dan framework
Kelemahan:
- Distribusi acak menyebabkan fragmentasi index B-tree. Pada tabel write-heavy dengan jutaan baris, primary key v4 dapat menurunkan performa insert hingga 2–10x dibanding ID sekuensial karena page split yang berlebihan.
// Generate UUID v4 — bawaan di semua browser modern dan Node.js
const id = crypto.randomUUID();
// → "550e8400-e29b-41d4-a716-446655440000"
UUID v5 — Hash Deterministik
UUID v5 melakukan hash namespace UUID dan string name menggunakan SHA-1 untuk menghasilkan UUID deterministik. Input yang sama selalu menghasilkan output yang sama.
Kasus penggunaan: menghasilkan ID stabil dari URL, nama DNS, atau input yang dapat direproduksi. Pilih v5 daripada v3 (yang menggunakan MD5 yang lebih lemah).
import uuid
# Input sama → UUID sama, setiap saat
id = uuid.uuid5(uuid.NAMESPACE_DNS, "example.com")
# → "cfbff0d1-9375-5685-968c-48ce8b15ae17"
UUID v7 — Acak Terurut Waktu (Direkomendasikan)
UUID v7 (RFC 9562, Mei 2024) menyematkan timestamp Unix 48-bit dalam milidetik di bit paling signifikan, diikuti oleh 74 bit keacakan kriptografis.
Mengapa v7 menjadi default baru untuk key database:
- Insert sekuensial: UUID baru selalu lebih besar dari sebelumnya (dalam presisi milidetik), sehingga insert B-tree selalu menambahkan di akhir index
- Hingga 90% lebih sedikit page split dibanding v4 pada workload write-heavy
- Pengurutan kronologis alami tanpa kolom
created_attambahan - Tipe kolom
uuidstandar — tidak perlu perubahan skema jika bermigrasi dari v4 - 74 bit keacakan — cukup untuk hampir semua aplikasi (v4 memiliki 122 bit)
Trade-off: timestamp pembuatan tertanam dalam ID. Jika Anda memerlukan ID opaque yang tidak mengungkapkan waktu pembuatan, tetap gunakan v4.
// Pembuatan UUID v7 (Node.js 20+)
import { v7 as uuidv7 } from "uuid";
const id = uuidv7();
// → "01906b5e-4a3e-7234-8f56-b8c12d4e5678"
// ID lama selalu terurut sebelum yang baru
Performa PostgreSQL & MySQL: v4 vs v7
Benchmark pada tabel PostgreSQL 16 dengan 50 juta baris (primary key B-tree):
| Metrik | UUID v4 | UUID v7 | Peningkatan |
|---|---|---|---|
| Throughput insert (baris/detik) | 12.400 | 28.600 | 2,3x lebih cepat |
| Ukuran index setelah 50M baris | 4,2 GB | 2,8 GB | 33% lebih kecil |
| Page split selama bulk insert | 1,2M | 84K | 93% lebih sedikit |
| Sequential scan setelah insert | 320 ms | 180 ms | 44% lebih cepat |
Di MySQL/InnoDB, dampaknya bahkan lebih dramatis karena primary key ADALAH clustered index — UUID v4 acak memaksa reorganisasi halaman terus-menerus, sementara v7 berperilaku seperti auto-increment.
Skema ID Alternatif
ULID — Juara Sebelum v7
ULID (Universally Unique Lexicographically Sortable Identifier) dibuat pada 2016 untuk menyelesaikan masalah sortability UUID v4. ULID mengenkode timestamp milidetik 48-bit diikuti oleh 80 bit keacakan dalam string Crockford Base32 sepanjang 26 karakter.
01AN4Z07BY 79KA1307SR9X4MV3
|----------| |----------------|
Timestamp Keacakan
48 bit 80 bit
ULID vs UUID v7 — haruskah Anda beralih?
| Aspek | ULID | UUID v7 |
|---|---|---|
| Sortable | Ya | Ya |
| Panjang string | 26 karakter | 36 karakter |
| Penyimpanan | 16 byte | 16 byte |
| Standar | Spesifikasi komunitas | IETF RFC 9562 |
| Tipe DB native | Tidak (CHAR(26) atau BYTEA) | Ya (uuid) |
| Dukungan bahasa | npm, PyPI, crates.io | Bawaan di sebagian besar standard library |
Verdict: Jika Anda memulai dari awal, gunakan UUID v7 — memiliki sortability yang sama dengan dukungan ekosistem yang jauh lebih baik dan tipe database native. Jika Anda sudah menggunakan ULID, tidak ada kebutuhan mendesak untuk bermigrasi; keduanya secara fungsional setara.
Snowflake ID — Sistem Terdistribusi Throughput Tinggi
Snowflake ID (dibuat oleh Twitter pada 2010) mengemas integer 64-bit dengan:
0 | 41 bit timestamp | 10 bit worker ID | 12 bit sequence
- Timestamp 41-bit: milidetik sejak epoch kustom (~69 tahun rentang)
- Worker ID 10-bit: mendukung 1.024 worker unik
- Sequence 12-bit: hingga 4.096 ID per milidetik per worker
Kelebihan:
- 8 byte — setengah ukuran UUID/ULID, muat di kolom
BIGINT - Monotonik dalam satu worker — pengurutan terjamin per node
- 4,096 juta ID/detik throughput teoretis per worker
- Mudah dibaca sebagai integer biasa
Kelemahan:
- Memerlukan koordinasi terpusat — worker ID harus dialokasikan dan dikelola (biasanya via ZooKeeper, etcd, atau config service)
- Sensitif terhadap clock skew — jika jam sistem bergeser, ID bisa bertabrakan atau mundur
- Epoch kustom — setiap implementasi memilih epoch sendiri, membuat interop lintas sistem lebih sulit
- Bukan standar — puluhan varian yang tidak kompatibel (Twitter, Discord, Instagram, dll.)
// Pembuatan Snowflake ID (menggunakan sony/sonyflake)
package main
import (
"fmt"
"github.com/sony/sonyflake"
)
func main() {
sf := sonyflake.NewSonyflake(sonyflake.Settings{})
id, _ := sf.NextID()
fmt.Println(id) // → 175928847299543040
}
Kapan memilih Snowflake: sistem Anda menghasilkan >100K ID/detik, Anda memerlukan integer 64-bit yang kompak, dan Anda sudah memiliki infrastruktur untuk alokasi worker ID (misalnya, Kubernetes pod ordinal).
NanoID — ID URL-Safe yang Kompak
NanoID menghasilkan identifier pendek (default 21 karakter) yang URL-safe menggunakan alfabet A-Za-z0-9_-. Menggunakan crypto.getRandomValues() untuk keamanan.
import { nanoid } from "nanoid";
const id = nanoid(); // → "V1StGXR8_Z5jdHi6B-myT"
const short = nanoid(10); // → "IRFa-VaY2b"
Terbaik untuk: URL pendek, key komponen frontend, kode undangan, nama file — di mana pun panjang string penting dan Anda tidak memerlukan pengurutan level database atau interoperabilitas lintas sistem.
Tidak ideal untuk: primary key database (tanpa tipe DB native, tanpa sortability, tanpa timestamp).
CUID2 — Tahan Collision pada Skala Besar
CUID2 menghasilkan ID dengan panjang variabel yang dirancang untuk scaling horizontal. Menggabungkan counter, timestamp, fingerprint, dan keacakan.
Kasus penggunaan niche: sistem yang memerlukan ketahanan collision di banyak generator independen tanpa koordinasi. Dalam praktiknya, UUID v7 mencakup kebutuhan ini dengan standardisasi yang lebih baik.
Tabel Perbandingan Komprehensif
| Fitur | UUID v4 | UUID v7 | ULID | Snowflake | NanoID |
|---|---|---|---|---|---|
| Panjang | 36 karakter | 36 karakter | 26 karakter | 15–20 digit | 21 karakter (default) |
| Penyimpanan | 16 byte | 16 byte | 16 byte | 8 byte | ~21 byte |
| Sortable | Tidak | Ya (waktu) | Ya (waktu) | Ya (waktu) | Tidak |
| Timestamp | Tidak | 48-bit ms | 48-bit ms | 41-bit ms | Tidak |
| Keacakan | 122 bit | 74 bit | 80 bit | 12-bit seq | ~126 bit |
| Standar | RFC 9562 | RFC 9562 | Komunitas | Proprietary | Komunitas |
| Tipe DB native | uuid | uuid | Tidak | BIGINT | Tidak |
| Koordinasi | Tidak ada | Tidak ada | Tidak ada | Registri worker | Tidak ada |
| URL-safe | Tidak (tanda hubung) | Tidak (tanda hubung) | Ya | Ya (integer) | Ya |
| Collision pada 1M ID | ~10⁻²² | ~10⁻¹⁸ | ~10⁻²⁰ | Nol (monotonik) | ~10⁻²¹ |
Contoh Kode: Menghasilkan Setiap Tipe ID
JavaScript / TypeScript
import { v4 as uuidv4, v7 as uuidv7 } from "uuid";
import { ulid } from "ulid";
import { nanoid } from "nanoid";
// UUID v4
console.log(uuidv4());
// → "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d"
// UUID v7
console.log(uuidv7());
// → "01906b5e-4a3e-7234-8f56-b8c12d4e5678"
// ULID
console.log(ulid());
// → "01ARZ3NDEKTSV4RRFFQ69G5FAV"
// NanoID
console.log(nanoid());
// → "V1StGXR8_Z5jdHi6B-myT"
Python
import uuid
from ulid import ULID
from nanoid import generate
# UUID v4
print(uuid.uuid4())
# → "a8098c1a-f86e-11da-bd1a-00112444be1e"
# UUID v7 (Python 3.14+ direncanakan, atau gunakan paket uuid7)
from uuid_extensions import uuid7
print(uuid7())
# → "01906b5e-4a3e-7234-8f56-b8c12d4e5678"
# ULID
print(ULID())
# → "01ARZ3NDEKTSV4RRFFQ69G5FAV"
# NanoID
print(generate(size=21))
# → "V1StGXR8_Z5jdHi6B-myT"
Go
package main
import (
"fmt"
"github.com/google/uuid" // UUID v4 & v7
"github.com/oklog/ulid/v2" // ULID
gonanoid "github.com/matoous/go-nanoid/v2" // NanoID
)
func main() {
// UUID v4
fmt.Println(uuid.New())
// → "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d"
// UUID v7
fmt.Println(uuid.Must(uuid.NewV7()))
// → "01906b5e-4a3e-7234-8f56-b8c12d4e5678"
// ULID
fmt.Println(ulid.Make())
// → "01ARZ3NDEKTSV4RRFFQ69G5FAV"
// NanoID
id, _ := gonanoid.New()
fmt.Println(id)
// → "V1StGXR8_Z5jdHi6B-myT"
}
Migrasi dari UUID v4 ke v7
Jika sistem Anda sudah menggunakan primary key UUID v4 dan Anda ingin manfaat performa v7, berikut kabar baiknya: v4 dan v7 memiliki format 128-bit yang sama dan disimpan dalam tipe kolom uuid yang sama. Tidak perlu migrasi skema.
Strategi Migrasi
- Record baru gunakan v7, record lama tetap v4. Keduanya berdampingan dalam kolom yang sama. Query dan join bekerja identik.
- Update kode pembuatan ID Anda — ganti
uuidv4()denganuuidv7()di application layer. - JANGAN tulis ulang ID v4 yang sudah ada. Ini akan merusak foreign key, referensi eksternal, dan URL yang di-cache.
- Pantau performa index. Seiring rasio v4/v7 bergeser ke v7, fragmentasi index akan secara bertahap berkurang.
Pemeriksaan Kompatibilitas
-- v4 dan v7 berdampingan dalam kolom uuid yang sama
SELECT id, version FROM (
SELECT id,
CASE get_byte(id::bytea, 6) >> 4
WHEN 4 THEN 'v4'
WHEN 7 THEN 'v7'
ELSE 'other'
END AS version
FROM your_table
) t
GROUP BY version;
Pertanyaan yang Sering Diajukan
Haruskah saya menggunakan UUID v7 atau auto-increment integer?
Auto-increment integer lebih sederhana dan lebih kecil (4–8 byte vs 16 byte), tapi memerlukan sequence terpusat — hanya database yang bisa menghasilkannya. UUID v7 dapat dibuat di mana saja (client, edge, microservice) tanpa round trip database. Gunakan auto-increment untuk aplikasi single-database sederhana; gunakan UUID v7 untuk sistem terdistribusi, arsitektur multi-tenant, atau ketika Anda memerlukan pembuatan ID di sisi client.
Apakah 74 bit keacakan UUID v7 cukup?
Ya. 74 bit acak memberikan 2⁷⁴ ≈ 1,9 × 10²² nilai yang mungkin per milidetik. Bahkan menghasilkan 1 juta ID per milidetik, probabilitas collision kira-kira 10⁻¹⁰ — jauh di bawah kekhawatiran praktis apa pun. 122 bit acak UUID v4 berlebihan untuk sebagian besar aplikasi.
Bisakah saya mengekstrak timestamp dari UUID v7?
Ya. 48 bit pertama mengenkode timestamp Unix dalam milidetik:
function extractTimestamp(uuidv7) {
const hex = uuidv7.replace(/-/g, "").slice(0, 12);
const ms = parseInt(hex, 16);
return new Date(ms);
}
extractTimestamp("01906b5e-4a3e-7234-8f56-b8c12d4e5678");
// → 2024-07-01T12:34:56.000Z
Ini adalah fitur, bukan bug — tapi jika Anda memerlukan ID opaque, gunakan v4.
Apakah PostgreSQL 18 mendukung UUID v7 secara native?
PostgreSQL 18 (dirilis 2025) menambahkan fungsi uuidv7() bawaan, menghilangkan kebutuhan ekstensi seperti pgcrypto atau pg_uuidv7. MySQL belum memiliki pembuatan v7 native — buat di application layer Anda.
Mengapa tidak langsung pakai ULID?
ULID mendahului UUID v7 dan menyelesaikan masalah yang sama. Sekarang v7 adalah standar IETF (RFC 9562), ia memiliki keunggulan kunci: tipe database uuid native (16 byte, diindex secara efisien), dukungan bahasa/framework yang lebih luas, dan standardisasi formal. Jika Anda sudah menggunakan ULID, ia bekerja dengan baik — tidak perlu bermigrasi. Untuk proyek baru, pilih UUID v7.
Kapan Snowflake ID menjadi pilihan yang lebih baik?
Ketika Anda memerlukan ID 64-bit yang kompak pada throughput ekstrem (>100K ID/detik per node) dan sudah memiliki infrastruktur untuk alokasi worker ID. Penyimpanan BIGINT 8 byte Snowflake adalah setengah ukuran UUID, yang penting pada miliaran baris. Trade-off-nya adalah kompleksitas operasional: Anda harus mengelola alokasi worker ID dan menangani clock skew.
Perlu membuat UUID sekarang? Coba UUID Generator kami — mendukung v1, v4, v5, dan v7 dengan pembuatan batch dan decoding, 100% di browser Anda.