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(hex7). - 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
10per 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 →