Which UUID version to use?

Learn which uuid version to use? with practical examples, diagrams, and best practices. Covers uuid development techniques with visual explanations.

Choosing the Right UUID Version: A Comprehensive Guide

Hero image for Which UUID version to use?

Understand the different UUID versions (v1, v4, v6, v7, v8) and learn how to select the most appropriate one for your application's needs, considering factors like uniqueness, privacy, and sortability.

Universally Unique Identifiers (UUIDs), also known as Globally Unique Identifiers (GUIDs), are 128-bit numbers used to uniquely identify information in computer systems. They are designed to be unique across all space and time, making collisions extremely unlikely. While the concept is straightforward, several versions of UUIDs exist, each with different generation mechanisms and characteristics. Choosing the correct version is crucial for optimizing performance, ensuring privacy, and maintaining data integrity in your applications.

Understanding UUID Versions

The Internet Engineering Task Force (IETF) defines UUIDs in RFC 4122, outlining several versions. Each version employs a distinct algorithm for generating the identifier, leading to different properties regarding uniqueness, predictability, and sortability. Let's explore the most common and relevant versions.

flowchart TD
    A[Start] --> B{UUID Version Selection}
    B -->|Need Time-based & Sortable?| C[UUIDv1 (MAC + Timestamp)]
    B -->|Need Random & Unpredictable?| D[UUIDv4 (Random)]
    B -->|Need Time-based & Sortable (Improved)?| E[UUIDv6 (Reordered Timestamp)]
    B -->|Need Time-based, Sortable & Semantic?| F[UUIDv7 (Unix Epoch + Random)]
    B -->|Need Custom Logic?| G[UUIDv8 (Custom)]
    C --> H[Use UUIDv1]
    D --> I[Use UUIDv4]
    E --> J[Use UUIDv6]
    F --> K[Use UUIDv7]
    G --> L[Use UUIDv8]
    H,I,J,K,L --> M[End]

Decision flow for choosing a UUID version based on application requirements.

UUIDv1: Time-based and MAC Address Dependent

UUIDv1 combines the current timestamp with the MAC address of the generating machine. This ensures uniqueness across different machines and provides a degree of temporal ordering. However, the inclusion of the MAC address raises privacy concerns, as it can potentially reveal the identity of the generating device. While sortable by generation time, the MAC address component can make them less ideal for public-facing identifiers.

import uuid

# Generate a UUIDv1
v1_uuid = uuid.uuid1()
print(f"UUIDv1: {v1_uuid}")
print(f"Is UUIDv1 time-based? {v1_uuid.is_safe == uuid.SafeUUID.safe}")

Example of generating a UUIDv1 in Python.

UUIDv4: Purely Random

UUIDv4 is the most commonly used version. It generates UUIDs using entirely random numbers (or pseudo-random numbers). This makes them highly unpredictable and excellent for privacy, as they contain no discernible information about their origin or generation time. The primary drawback is that they are not inherently sortable, which can lead to performance issues when used as primary keys in indexed databases, as new entries can be inserted anywhere, causing index fragmentation.

import { v4 as uuidv4 } from 'uuid';

// Generate a UUIDv4
const v4_uuid = uuidv4();
console.log(`UUIDv4: ${v4_uuid}`);

Generating a UUIDv4 using a common JavaScript library.

UUIDv6 and UUIDv7: The Future of Sortable UUIDs

Recognizing the limitations of UUIDv1 (privacy) and UUIDv4 (sortability), newer versions have emerged to offer the best of both worlds. UUIDv6 reorders the components of a UUIDv1 to place the timestamp first, making it lexicographically sortable while still being time-based. UUIDv7 takes this a step further by using a Unix Epoch timestamp, providing a more standardized and efficient time component, combined with a random component. Both UUIDv6 and UUIDv7 aim to provide sortable, time-ordered identifiers without the privacy concerns of exposing a MAC address.

package main

import (
	"fmt"
	"github.com/gofrs/uuid"
)

func main() {
	// UUIDv6 (requires a library that supports it, e.g., gofrs/uuid)
	v6_uuid, err := uuid.NewV6()
	if err != nil {
		fmt.Printf("Error generating UUIDv6: %v\n", err)
		return
	}
	fmt.Printf("UUIDv6: %s\n", v6_uuid.String())

	// UUIDv7 (requires a library that supports it)
	v7_uuid, err := uuid.NewV7()
	if err != nil {
		fmt.Printf("Error generating UUIDv7: %v\n", err)
		return
	}
	fmt.Printf("UUIDv7: %s\n", v7_uuid.String())
}

Generating UUIDv6 and UUIDv7 in Go (using a third-party library).

UUIDv8: Custom and Application-Specific

UUIDv8 is a custom format that allows developers to define their own algorithm for generating the UUID. This version is intended for highly specialized use cases where existing UUID versions do not meet specific requirements. It provides flexibility but also places the burden of ensuring uniqueness and other desired properties entirely on the implementer. Use UUIDv8 only if you have a clear, well-defined need that cannot be met by other versions.