Password Generator

UUID v7 Guide

The modern, sortable UUID — what it is and how to use it

Skip straight to the UUID v7 generator or keep reading to understand what makes UUID v7 the preferred choice for new projects.

What is UUID v7?

UUID Version 7 (UUIDv7) is a time-ordered, randomly padded unique identifier defined in RFC 9562 (the successor to RFC 4122). Like all UUIDs it is 128 bits long and expressed as a 32-character hex string split by hyphens:

01956399-e5c4-7a3b-b7f2-4c9d08e1a2f3
└───────┘ └──┘ └───┘ └───────────────┘
 48-bit    ver  rand     rand (62 bits)
 Unix ms   (7)

The first 48 bits encode the current Unix timestamp in milliseconds. The next 4 bits are always 0111 (the version nibble 7). The remaining 74 bits are filled with cryptographically secure random data. This layout makes UUIDv7 values lexicographically sortable — a batch generated in sequence will sort in creation order without any extra work.

Why choose UUID v7?

Compared to UUID v4 (random)

UUID v4 is purely random. That is great for uniqueness, but random identifiers scatter data across B-tree indexes, causing index fragmentation and slower writes as a table grows. UUID v7 keeps new rows near the end of the index because its timestamp prefix is always increasing, giving you much better database write performance — especially on PostgreSQL, MySQL, and SQL Server.

Compared to UUID v1 (time + MAC)

UUID v1 also embeds a timestamp, but it encodes a 100-nanosecond clock and mixes the timestamp bits in a non-sortable order (the low-time bits come first). It also leaks the MAC address of the generating machine, which is a privacy concern. UUID v7 fixes both: it uses a simple 48-bit Unix millisecond timestamp, places it at the front so sorting works naturally, and uses random bits instead of a hardware address.

Compared to UUID v6

UUID v6 was a stepping stone — it reorders the UUID v1 timestamp for sortability but keeps the legacy 100 ns clock and MAC-address field. UUID v7 starts fresh with a clean, simple design based on the widely understood Unix millisecond timestamp. For new code, prefer v7 over v6.

When to still use UUID v4

If you need identifiers that carry no timing information whatsoever and your database is small or the insert rate is low, UUID v4 remains a fine choice. UUID v7 is recommended when you care about index performance or need natural time-ordering.

UUID v7 format in detail

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                           unix_ts_ms (high 32 bits)           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          unix_ts_ms (low 16)  |  ver (4) |  rand_a (12 bits)  |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var (2)|               rand_b (62 bits)                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       rand_b (continued)                      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  • unix_ts_ms (bits 0–47): milliseconds since the Unix epoch. At the typical generation rate this is safe until the year 10,895.
  • ver (bits 48–51): always 0111 (hex 7).
  • rand_a (bits 52–63): 12 random bits. Some implementations use these for a sub-millisecond sequence counter to keep monotonic ordering within the same millisecond.
  • var (bits 64–65): always 10 per RFC 9562 (the "Leach–Salz" variant).
  • rand_b (bits 66–127): 62 random bits generated by a cryptographically secure PRNG.

Code examples

uuid npm package

The uuid package added v7 support in v9.0.

# Install
npm install uuid
import { v7 as uuidv7 } from 'uuid';

const id = uuidv7();
console.log(id);
// → "01956399-e5c4-7a3b-b7f2-4c9d08e1a2f3"

Vanilla JS — no dependencies

If you would rather avoid an npm package, this minimal implementation follows the RFC 9562 layout.

function uuidv7() {
  const ts  = BigInt(Date.now());
  const rnd = new Uint8Array(10);
  crypto.getRandomValues(rnd);

  const b = new Uint8Array(16);
  // 48-bit Unix ms timestamp
  b[0] = Number((ts >> 40n) & 0xffn);
  b[1] = Number((ts >> 32n) & 0xffn);
  b[2] = Number((ts >> 24n) & 0xffn);
  b[3] = Number((ts >> 16n) & 0xffn);
  b[4] = Number((ts >>  8n) & 0xffn);
  b[5] = Number( ts        & 0xffn);
  // version 7 + 12 random bits
  b[6] = 0x70 | (rnd[0] & 0x0f);
  b[7] = rnd[1];
  // variant 10xx + 62 random bits
  b[8] = 0x80 | (rnd[2] & 0x3f);
  for (let i = 0; i < 7; i++) b[9 + i] = rnd[3 + i];

  const h = [...b].map(x => x.toString(16).padStart(2, '0')).join('');
  return `${h.slice(0,8)}-${h.slice(8,12)}-${h.slice(12,16)}-${h.slice(16,20)}-${h.slice(20)}`;
}

console.log(uuidv7());

TypeScript — typed helper

import { v7 as uuidv7 } from 'uuid';

/** Returns a time-ordered UUID v7 string. */
function newId(): string {
  return uuidv7();
}

interface Entity {
  id: string;
  createdAt: Date;
}

function createEntity(): Entity {
  return { id: newId(), createdAt: new Date() };
}

Python 3.12+ — standard library

Python 3.12 added uuid.uuid7() to the standard library.

import uuid

# Python 3.12+
uid = uuid.uuid7()
print(uid)
# → 01956399-e5c4-7a3b-b7f2-4c9d08e1a2f3

Older Python — uuid6 package

For Python < 3.12, install the uuid6 backport.

# Install
pip install uuid6
import uuid6

uid = uuid6.uuid7()
print(uid)
print(uid.version)  # 7

Extract the timestamp from a UUID v7

import uuid
from datetime import datetime, timezone

uid = uuid.uuid7()
# First 48 bits are the Unix timestamp in milliseconds
ms  = uid.int >> 80
dt  = datetime.fromtimestamp(ms / 1000, tz=timezone.utc)
print(dt)  # e.g. 2026-04-07 14:23:11.456+00:00

google/uuid

# Install
go get github.com/google/uuid
package main

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

func main() {
    id, err := uuid.NewV7()
    if err != nil {
        panic(err)
    }
    fmt.Println(id)
}

GORM model with UUID v7 primary key

import "github.com/google/uuid"

type Event struct {
    ID        uuid.UUID  `gorm:"type:uuid;primaryKey"`
    Name      string
    CreatedAt time.Time
}

func (e *Event) BeforeCreate(tx *gorm.DB) error {
    id, err := uuid.NewV7()
    if err != nil {
        return err
    }
    e.ID = id
    return nil
}

java-uuid-generator

The java-uuid-generator (JUG) library supports UUIDv7.

<!-- Maven -->
<dependency>
    <groupId>com.fasterxml.uuid</groupId>
    <artifactId>java-uuid-generator</artifactId>
    <version>5.1.0</version>
</dependency>
import com.fasterxml.uuid.Generators;
import java.util.UUID;

UUID id = Generators.timeBasedEpochGenerator().generate();
System.out.println(id);
// → 01956399-e5c4-7a3b-b7f2-4c9d08e1a2f3

Spring Boot — JPA entity with UUID v7

import com.fasterxml.uuid.Generators;
import jakarta.persistence.*;
import java.util.UUID;

@Entity
public class Order {

    @Id
    private UUID id = Generators.timeBasedEpochGenerator().generate();

    private String customerName;
    private double total;
}

.NET 9+ — Guid.CreateVersion7()

.NET 9 ships native UUID v7 support. No NuGet packages required.

// Requires .NET 9+
var id = Guid.CreateVersion7();
Console.WriteLine(id);

// With an explicit timestamp
var id2 = Guid.CreateVersion7(DateTimeOffset.UtcNow);

.NET 8 and earlier — UuidExtensions NuGet

# Install
dotnet add package UUIDNext
using UUIDNext;

var id = Uuid.NewSequential();  // generates a UUID v7
Console.WriteLine(id);

Entity Framework Core — UUID v7 primary key

public class Product
{
    // .NET 9+: time-ordered primary key, no fragmentation
    public Guid Id { get; init; } = Guid.CreateVersion7();
    public string Name { get; set; }
}

ramsey/uuid 4.7+

# Install
composer require ramsey/uuid
use Ramsey\Uuid\Uuid;

$id = Uuid::uuid7()->toString();
echo $id;
// → 01956399-e5c4-7a3b-b7f2-4c9d08e1a2f3

Laravel — UUID v7 primary key

use Illuminate\Database\Eloquent\Concerns\HasUlids;
use Illuminate\Database\Eloquent\Model;
use Ramsey\Uuid\Uuid;

class Event extends Model
{
    public static function boot(): void
    {
        parent::boot();
        static::creating(function ($model) {
            $model->id = Uuid::uuid7()->toString();
        });
    }
}

uuidtools gem

# Install
gem install uuidtools
require 'uuidtools'

puts UUIDTools::UUID.uuid_v7

Rails — UUID v7 model ID

# config/initializers/generators.rb
Rails.application.config.generators do |g|
  g.orm :active_record, primary_key_type: :uuid
end

# app/models/event.rb
class Event < ApplicationRecord
  before_create { self.id = UUIDTools::UUID.uuid_v7.to_s }
end

uuid crate with v7 feature

# Cargo.toml
[dependencies]
uuid = { version = "1", features = ["v7"] }
use uuid::Uuid;

fn main() {
    let id = Uuid::now_v7();
    println!("{}", id);
}

Diesel ORM — UUID v7 primary key

use uuid::Uuid;

#[derive(Insertable)]
#[diesel(table_name = events)]
struct NewEvent {
    id:    Uuid,
    title: String,
}

impl NewEvent {
    fn new(title: String) -> Self {
        NewEvent { id: Uuid::now_v7(), title }
    }
}

Elixir UUID package

Generate UUID v7 values in Elixir using a UUID library with v7 support.

# mix.exs dependencies
{:uuid, "~> 2.0"}
UUID = Elixir.UUID

id = UUID.uuid7()
IO.puts(id)

Erlang uuid library

Generate UUID v7 values in Erlang with a UUID dependency.

% rebar.config
{deps, [{uuid, "*"}]}
UUID = uuid:uuid7().
io:format("~s~n", [UUID]).

PostgreSQL 17+

PostgreSQL 17 ships with a native uuidv7() function.

-- Generate a UUID v7 (PostgreSQL 17+)
SELECT uuidv7();

-- Table with UUID v7 default primary key
CREATE TABLE events (
    id         UUID PRIMARY KEY DEFAULT uuidv7(),
    name       TEXT NOT NULL,
    created_at TIMESTAMPTZ DEFAULT now()
);

-- Extract the timestamp from a UUID v7
SELECT to_timestamp(
    (get_byte(id::bytea, 0)::bigint << 40 |
     get_byte(id::bytea, 1)::bigint << 32 |
     get_byte(id::bytea, 2)::bigint << 24 |
     get_byte(id::bytea, 3)::bigint << 16 |
     get_byte(id::bytea, 4)::bigint <<  8 |
     get_byte(id::bytea, 5)::bigint) / 1000.0
) FROM events LIMIT 1;

PostgreSQL < 17 — custom function

-- Works on PostgreSQL 13–16
CREATE OR REPLACE FUNCTION uuidv7() RETURNS uuid
LANGUAGE plpgsql AS $$
DECLARE
    v_time    NUMERIC := NULL;
    v_hex     TEXT    := NULL;
BEGIN
    v_time := (EXTRACT(EPOCH FROM clock_timestamp()) * 1000)::BIGINT;
    v_hex  := lpad(to_hex(v_time), 12, '0')
           || '7'
           || lpad(to_hex(floor(random() * 4096)::int), 3, '0')
           || lpad(to_hex(floor(random() * 16384)::int | 32768), 4, '0')
           || lpad(to_hex(floor(random() * 281474976710656)::bigint), 12, '0');
    RETURN (
        substring(v_hex, 1, 8) || '-' ||
        substring(v_hex, 9, 4) || '-' ||
        substring(v_hex, 13, 4) || '-' ||
        substring(v_hex, 17, 4) || '-' ||
        substring(v_hex, 21, 12)
    )::uuid;
END;
$$;

MySQL 8 / MariaDB

MySQL has no native UUID v7 function. Generate in the application layer and store as CHAR(36) or BINARY(16).

-- Store as BINARY(16) for optimal index performance
CREATE TABLE events (
    id   BINARY(16) PRIMARY KEY,
    name VARCHAR(200)
);

-- Insert from application (Python example)
-- cursor.execute("INSERT INTO events VALUES (%s, %s)",
--     (uuid.uuid7().bytes, "signup"))

SQL Server

SQL Server has no built-in UUID v7. Use NEWSEQUENTIALID() as a placeholder, or generate v7 in the application and insert as UNIQUEIDENTIFIER.

CREATE TABLE Events (
    Id    UNIQUEIDENTIFIER PRIMARY KEY DEFAULT NEWSEQUENTIALID(),
    Title NVARCHAR(200)
);
-- Or pass the UUID v7 value directly from your application.

Frequently asked questions

Is UUID v7 an official standard?

Yes. UUID v7 is defined in RFC 9562 (May 2024), which supersedes RFC 4122. It is a stable, published IETF standard.

Can I sort UUID v7 values as strings?

Yes — because the timestamp occupies the highest-order bits and UUIDs are represented in big-endian order, a simple lexicographic sort (alphabetical) on the UUID string produces chronological order. This works in SQL ORDER BY, JavaScript Array.sort(), and virtually every sort algorithm.

Can two UUID v7 values generated at the same millisecond collide?

Extremely unlikely. Even at the same millisecond, 74 bits of randomness remain (about 18.8 quintillion combinations). For applications that generate many IDs per millisecond on a single node some libraries offer a monotonic sub-millisecond counter in the rand_a field to guarantee strict ordering within a millisecond, at the cost of slightly less randomness.

Does UUID v7 reveal when a record was created?

Yes — anyone who has the UUID can extract a millisecond-precise UTC timestamp from it. If the creation time of a record is sensitive, use UUID v4 instead.

Should I migrate existing UUID v4 columns to UUID v7?

For existing columns it is usually not worth the migration cost unless you are experiencing write-amplification problems from index fragmentation. Use UUID v7 for new tables or services where you control the ID generation from the start.

Ready to generate? Open the UUID v7 generator →