UUID v7 Generator

Generate time-ordered UUID v7 for database primary keys

Format

Count:

What is UUID v7?

UUID v7 is a next-generation UUID format standardised in RFC 9562 (May 2024). It encodes a 48-bit Unix millisecond timestamp in the most-significant bits, followed by version and variant markers, and fills the remaining bits with cryptographically secure random data.

Because the timestamp occupies the high bits, UUID v7 values sort chronologically — both lexicographically and numerically. This makes them an excellent fit for database primary keys, where random UUIDs (v4) cause B-tree index fragmentation.

Why Random UUIDs Fragment Database Indexes

B-tree indexes — used by PostgreSQL, MySQL, SQLite, and most other databases — keep rows sorted by key value. When you insert a new row, the database must place it in the correct sorted position within the index.

With UUID v4 (fully random), each new insert lands at an essentially random position in the index tree. This forces the database to read and rewrite internal index pages constantly, splitting full pages and leaving others half-empty. The result is a fragmented, bloated index that slows both writes and reads as the table grows.

UUID v7 Bit Layout

UUID v7 is 128 bits wide, divided into six fields:

BitsFieldPurpose
48unix_ts_ms48-bit Unix timestamp in milliseconds — occupies the entire high half
4verVersion number — always 0111 (decimal 7)
12rand_a12 bits of cryptographically secure random data
2varVariant marker — always 10 (RFC 4122 variant)
62rand_b62 bits of cryptographically secure random data

The timestamp precision is 1 millisecond. Within the same millisecond, UUID v7 values are ordered by their random suffix — they are not guaranteed to be monotonically increasing sub-millisecond, but they are k-sortable: IDs generated close together in time will sort close together in the index.

UUID v7 vs UUID v1

Both UUID v1 and UUID v7 embed a timestamp, but they differ significantly in design:

FeatureUUID v7UUID v1
Epoch / Time BaseUnix epoch (Jan 1, 1970)Gregorian epoch (Oct 15, 1582)
Time Precision1 millisecond100 nanoseconds
SortableYes — k-sortable by designNo — time fields are scrambled in the UUID layout
PrivacyNo host information leakedEmbeds MAC address of generating host
DB Index PerformanceExcellent — sequential inserts, minimal fragmentationPoor — non-sequential despite timestamp
StandardRFC 9562 (2024)RFC 4122 (2005)
Native Browser SupportNot yet (no crypto.randomUUID v7)Not available natively

For any new project that needs time-ordered UUIDs, prefer UUID v7 over UUID v1. UUID v1 is legacy and leaks host information.

UUID v7 vs ULID

ULID (Universally Unique Lexicographically Sortable Identifier) solves a similar problem to UUID v7. Here is how they compare:

UUID v7
  • Follows the RFC 9562 UUID standard — compatible with all UUID tooling
  • Hyphenated hex format — universally recognized
  • Native database UUID column support
  • 128 bits total
ULID
  • Crockford Base32 encoding — 26 characters, slightly more compact
  • Case-insensitive and avoids ambiguous characters (I, L, O, U)
  • More human-readable at a glance
  • Requires a library — no native platform support

If you are already in a UUID ecosystem (PostgreSQL uuid column, REST APIs returning UUIDs), use UUID v7. If you are starting fresh and prefer a more human-friendly encoding, ULID is a reasonable alternative.

Using UUID v7 in Databases

UUID v7 is not yet natively generated by most databases, but it can be stored in standard UUID columns and generated in application code or via extensions:

PostgreSQL
PostgreSQL: store in a uuid column. The pg-uuidv7 extension adds a uuid_generate_v7() server-side function if you need DB-generated IDs.
MySQL / MariaDB
MySQL / MariaDB: store in a BINARY(16) or CHAR(36) column. Generate in application code. MySQL 8.0+ has ordered UUID support via UUID_TO_BIN(UUID(), 1) for v1, but v7 requires app-level generation.
SQLite
SQLite: store as TEXT (36 chars) or BLOB (16 bytes). Generate in application code. Lexicographic sort on TEXT works correctly because UUID v7 uses a fixed-width timestamp prefix.

Code Examples

UUID v7 is not yet available via crypto.randomUUID(). Use a library such as uuidv7 (npm) until native support arrives:

JavaScript (browser / Node.js 20+)
function generateUuidV7() {
  const buf = new Uint8Array(16)
  crypto.getRandomValues(buf)

  const ms = BigInt(Date.now())

  // Embed 48-bit Unix ms timestamp
  buf[0] = Number((ms >> 40n) & 0xFFn)
  buf[1] = Number((ms >> 32n) & 0xFFn)
  buf[2] = Number((ms >> 24n) & 0xFFn)
  buf[3] = Number((ms >> 16n) & 0xFFn)
  buf[4] = Number((ms >> 8n)  & 0xFFn)
  buf[5] = Number(ms & 0xFFn)

  // Set version 7 (0111xxxx)
  buf[6] = (buf[6] & 0x0F) | 0x70

  // Set variant (10xxxxxx)
  buf[8] = (buf[8] & 0x3F) | 0x80

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

// Node.js 20+ built-in
// import { randomUUID } from 'node:crypto'  // v4 only — no v7 yet in stdlib
Python (uuid7 library)
# pip install uuid7
import uuid_extensions

uid = uuid_extensions.uuid7()
print(uid)                       # e.g. 018e2b3d-1a2b-7000-8000-abc123456789
print(uid.time)                  # Unix ms timestamp embedded in the UUID

# Or as a plain string
from uuid_extensions import uuid7str
print(uuid7str())
PostgreSQL — generate UUID v7
-- PostgreSQL 13+ extension-free implementation
CREATE OR REPLACE FUNCTION uuid_generate_v7()
RETURNS uuid
LANGUAGE sql
AS $$
  SELECT encode(
    set_bit(
      set_bit(
        overlay(
          uuid_send(gen_random_uuid())
          PLACING substring(int8send(floor(extract(epoch FROM clock_timestamp()) * 1000)::bigint) FROM 3)
          FROM 1 FOR 6
        ),
        52, 1
      ),
      53, 1
    ),
    'hex'
  )::uuid;
$$;

-- Usage as a default primary key
CREATE TABLE events (
  id uuid PRIMARY KEY DEFAULT uuid_generate_v7(),
  payload jsonb,
  created_at timestamptz DEFAULT now()
);
TypeScript — extract timestamp from UUID v7
function extractTimestamp(uuid: string): Date {
  const hex = uuid.replace(/-/g, '')
  const ms = parseInt(hex.slice(0, 12), 16)  // first 48 bits = ms timestamp
  return new Date(ms)
}

const uid = '018e2b3d-1a2b-7000-8000-abc123456789'
console.log(extractTimestamp(uid).toISOString())
// → "2024-03-15T10:22:05.259Z"

Frequently Asked Questions

Is UUID v7 backward compatible with UUID v4?
Yes. UUID v7 uses the same 128-bit, 32-hex-digit, hyphenated wire format as all other UUID versions. Any system that stores or transmits UUIDs will accept a UUID v7 without changes. The version nibble (7) and variant bits identify it as v7 to tools that inspect UUID structure.
Does UUID v7 expose the generation timestamp?
Yes — the first 48 bits are a Unix millisecond timestamp, so anyone with the UUID can determine approximately when it was generated (to the nearest millisecond). If exposing creation time is a concern for your use case, use UUID v4 instead.
Can I use UUID v7 as a database primary key without a separate created_at column?
Yes. Because UUID v7 embeds a millisecond-precision timestamp, you can decode that value to get the approximate creation time. However, for clarity and indexability, many teams still keep an explicit created_at column and use UUID v7 only for the ID column.
How much entropy does UUID v7 have?
UUID v7 has 74 bits of random data (12 bits in rand_a + 62 bits in rand_b). This is slightly less than UUID v4's 122 bits but still provides an astronomically large collision-free space for practical use. The reduced randomness is the trade-off for gaining timestamp sortability.
Is UUID v7 supported natively in browsers or Node.js?
Not yet as of early 2025. The RFC 9562 standard was published in May 2024, and platform support is still catching up. Use the uuidv7 npm package for now. Native support via crypto.randomUUID({ version: 7 }) or similar APIs may arrive in future browser and Node.js releases.