UUID Version 8: Customising Your Identifiers While Maintaining Standards

    January 20, 2025
    9 min read
    Technical explainer
    Tutorial
    uuid
    conversion
    best-practices
    innovation

    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:

    code
    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
    go
    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): supports v8() with custom payloads
    • uuid (Rust): experimental layout builder
    • uuid-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 🦸‍♀️

    Generate Your Own UUIDs

    Ready to put this knowledge into practice? Try our UUID generators:

    Generate a Single UUID

    Create a UUID with our fast, secure generator

    Bulk UUID Generator

    Need multiple UUIDs? Generate them in bulk

    Summary

    This article explores the power and flexibility of UUID Version 8, introduced in RFC 9562, to create custom identifiers for specific system needs while still complying with the UUID format. Includes implementation examples and best practices.

    TLDR;

    UUIDv8 introduces a standard-compliant way to embed custom semantics into 128-bit identifiers.

    Key points to remember:

    • UUIDv8 allows developers to define their own layout in the payload bits
    • You can encode timestamps, shard IDs, or even metadata — while still being RFC 9562 compliant
    • Ideal for systems needing traceable or semantically rich UUIDs

    This flexibility is great for logging, security, and platform-specific routing, but it comes with trade-offs in portability and complexity.

    Cookie Consent

    We use cookies to enhance your experience on our website. By accepting, you agree to the use of cookies in accordance with our Privacy Policy.