Time-Based UUIDs: Leveraging Version 1 for Chronological Ordering

    April 29, 2024
    9 min read
    Technical explainer
    Tutorial
    uuid
    database
    best-practices

    When most people think of UUIDs, they think of chaos: random strings that can’t be sorted, predicted, or interpreted. That’s true — if you’re using UUIDv4.

    But what if you want some order?

    That’s where UUIDv1 comes in. It’s a time-based identifier that encodes creation time, enabling natural sort order and efficient querying for time-series data.

    Let’s take a look at how UUIDv1 works, when to use it, and the trade-offs you should be aware of.


    🧬 What Is UUIDv1?

    UUIDv1 is defined in [RFC 4122](https://datatracker.ietf.org/doc/html/rfc4122) and encodes:

    • 60 bits of timestamp (in 100-nanosecond intervals since Oct 15, 1582)
    • 48 bits of node ID (usually MAC address)
    • 14 bits of clock sequence (to prevent duplication)

    The layout ensures that UUIDs generated later will sort after those generated earlier — making UUIDv1 ideal for ordered data.


    📦 Why Use UUIDv1?

    UUIDv1 offers:

    • Globally unique identifiers
    • Natural chronological ordering
    • No central coordination
    • Fast generation

    This makes it perfect for:

    • Time-series logs
    • Message queues
    • Event sourcing
    • Append-only databases
    • Data replication where ordering matters

    ⚠️ Trade-Offs of UUIDv1

    Despite its benefits, UUIDv1 has some drawbacks:

    ❌ Privacy Risk

    • Encodes part of the MAC address
    • Reveals creation timestamp — down to 100ns

    ❌ Predictability

    • If you know the pattern, UUIDv1s are guessable in order
    • Not suitable for public identifiers or security tokens

    🧪 Generating UUIDv1 (Examples)

    🔹 Python

    python
    import uuid
    
    u = uuid.uuid1()
    print(u)

    Python’s uuid1() uses your machine’s MAC address and system time. You can override the node for privacy:

    python
    uuid.uuid1(node=0x123456789abc)

    🔹 Go (using github.com/gofrs/uuid)

    go
    package main
    
    import (
        "fmt"
        "github.com/gofrs/uuid"
    )
    
    func main() {
        id, _ := uuid.NewV1()
        fmt.Println("UUIDv1:", id)
    }

    🔹 Java

    java
    import com.fasterxml.uuid.Generators;
    import com.fasterxml.uuid.impl.TimeBasedGenerator;
    
    public class UUIDv1Example {
        public static void main(String[] args) {
            TimeBasedGenerator gen = Generators.timeBasedGenerator();
            System.out.println(gen.generate());
        }
    }

    📅 UUIDv1 for Time-Series Databases

    Because UUIDv1s sort chronologically, they’re a good fit for:

    • Time-ordered tables (e.g., in PostgreSQL or MySQL)
    • Index-friendly inserts (better than UUIDv4 for B-trees)
    • Range queries based on time

    PostgreSQL Tip

    sql
    CREATE TABLE events (
      id UUID PRIMARY KEY,
      event_data JSONB,
      created_at TIMESTAMPTZ DEFAULT NOW()
    );
    
    -- Index for time-range scanning
    CREATE INDEX ON events (id);

    With UUIDv1, ORDER BY id DESC roughly equals ORDER BY created_at DESC.


    🧰 Alternatives If UUIDv1 Isn't Right

    If you're concerned about leaking timestamps or MAC addresses:

    • UUIDv7: A newer spec that encodes timestamp + randomness without MAC
    • ULID: Lexicographically sortable, base32-encoded timestamped ID
    • Snowflake IDs: Used by Twitter, encodes timestamp + worker ID + sequence

    > TL;DR: Use UUIDv1 for internal ordered IDs, but not for public-facing identifiers.


    🔐 Security Considerations

    • Don’t expose UUIDv1 in URLs or public APIs
    • Be aware of info leaks from MAC address and creation time
    • Prefer UUIDv4, UUIDv7, or secure tokens for anything involving authentication

    Final Thoughts

    UUIDv1 might be old, but it’s far from obsolete. If your system needs order, uniqueness, and performance — and you’re not worried about exposing timestamps — it’s still a solid choice.

    Just use it wisely, and always understand the trade-offs before choosing an identifier format.

    🕒 UUIDv1: Because sometimes, order really does matter.

    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 UUIDv1 — the time-based version — showing how it enables chronological ordering and supports time-series data. Includes practical code examples and best practices for real-world implementation.

    TLDR;

    UUIDv1 is a time-based identifier that preserves natural order while maintaining global uniqueness.

    Key takeaways:

    • UUIDv1 encodes a timestamp and MAC address (or node ID)
    • It's ideal for time-series applications and ordered inserts
    • Use with caution: exposes creation time and potential system info

    When you need ordering and uniqueness without coordination, UUIDv1 is a powerful (if often misunderstood) tool.

    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.