What is UUIDv8?
UUID Version 8 (UUIDv8) is the most flexible version of UUID introduced in the latest standard — [RFC 9562](https://datatracker.ietf.org/doc/rfc9562/). It’s a game-changer for developers who need custom, semantically meaningful identifiers while still adhering to the 128-bit UUID format.
UUIDv8 provides a "bring-your-own-payload" approach. The only strict requirements are:
- Bits 48–51 must indicate version 8
- Bits 64–65 must follow the RFC-defined variant
Everything else? Yours to define.
Why Use UUIDv8?
You might reach for UUIDv8 when:
- You want to embed a timestamp or shard ID directly in your identifier
- You need sortable UUIDs but with more control than v7 allows
- You want to encode metadata, like environment or region info
- You're building cross-system integrations and need custom identifiers for routing, debugging, or compliance
All of this while remaining compliant with UUID tools, parsers, and validators.
UUIDv8 Bit Layout (Simplified)
Here’s how a UUID is structured:
Bits: 0 32 48 52 64 128
+--------+--------+----+--------+--------+
| time_hi | ver=8 |var | custom | |
+--------+--------+----+--------+--------+
- Bits 48–51 are fixed (
1000
for v8) - Bits 64–65 determine the variant (
10
for RFC compliant) - Remaining bits? Up to you
That gives you about 122 bits of custom space, minus reserved bits. Enough to fit:
- A UNIX timestamp
- A few flags
- A region or tenant ID
- And still have room for randomness
Practical Example: Custom UUIDv8 in Go
Let’s build a UUIDv8 that includes:
- A 42-bit UNIX timestamp (good until 2109)
- A 12-bit region code
- A 64-bit random suffix
package main
import (
"crypto/rand"
"encoding/binary"
"fmt"
"time"
)
func GenerateUUIDv8() string {
b := make([]byte, 16)
// 42-bit UNIX timestamp (seconds)
ts := uint64(time.Now().Unix())
binary.BigEndian.PutUint64(b[0:8], ts<<22)
// 12-bit region code (e.g., 0xA5B)
region := uint16(0xA5B)
b[5] |= byte(region >> 4)
b[6] |= byte((region & 0xF) << 4)
// Set version to 8 (01000)
b[6] &= 0x0F
b[6] |= 0x80
// Set variant to RFC 4122 (10xxxxxx)
b[8] &= 0x3F
b[8] |= 0x80
// Add random payload to the tail
_, _ = rand.Read(b[9:])
// Format as UUID string
return fmt.Sprintf("%08x-%04x-%04x-%04x-%012x",
binary.BigEndian.Uint32(b[0:4]),
binary.BigEndian.Uint16(b[4:6]),
binary.BigEndian.Uint16(b[6:8]),
binary.BigEndian.Uint16(b[8:10]),
b[10:])
}
func main() {
fmt.Println(GenerateUUIDv8())
}
This custom UUIDv8 embeds a timestamp and region code while still looking like a UUID to any validator.
Use Cases in the Wild
🔄 Event-Driven Systems
Embed an event timestamp directly into the ID — useful when event ordering matters but you don’t want to maintain external metadata.
🌍 Multi-Region Infrastructure
Generate UUIDs that carry region or zone info, helping route or debug cross-region traffic issues.
🔐 Security Tokens
Store user roles or scopes directly in a UUIDv8 for quick verification without DB lookups. (But beware of leaking sensitive info — always encrypt if needed.)
📜 Legacy ID Conversion
When migrating from legacy systems, UUIDv8 can carry old ID references or conversion metadata inline with new system requirements.
Compatibility Considerations
✅ Works With:
- Most UUID validators (as long as version and variant bits are set)
- Databases with native UUID support
- Indexing and partitioning strategies
❌ Be Cautious With:
- External APIs expecting only v1/v4
- Systems relying on randomness for uniqueness
- Tooling that assumes UUIDv8 doesn't exist (older libraries)
Before adopting UUIDv8 in a shared ecosystem, confirm that all your tools can parse but ignore the custom bits.
Best Practices for Using UUIDv8
- Define a spec for your UUIDv8 layout — document it for future maintainers
- Version your encodings inside the UUID to allow evolution
- Use UUIDv8 for internal use cases, not public-facing APIs (stick with UUIDv4/v7 there)
- Benchmark indexing performance — sortability may vary depending on bit layout
- Don't treat it as a cryptographic format — unless using proper hashing or encryption
Tooling and Libraries with UUIDv8 Support
As of 2025, these libraries have adopted v8:
uuid
(JS): supportsv8()
with custom payloadsuuid
(Rust): experimental layout builderuuid-tools
(CLI): format and parse v8 with custom templates- Go implementations (community): GitHub projects like
uuidv8-go
Expect broader support as UUIDv8 gets more adoption in IoT, observability, and edge systems.
Final Thoughts
UUIDv8 opens up a new chapter in the evolution of unique identifiers. It allows us to preserve compatibility with tools while building smarter IDs that carry their own intent.
Used wisely, UUIDv8 can help eliminate dependency on external metadata, simplify routing, and improve traceability — all without reinventing the wheel.
Just remember: with great power comes great UUID layout design 🦸♀️