pg_uuid_v8

UUID v8 generator with embedded timestamps for PostgreSQL

Overview

PackageVersionCategoryLicenseLanguage
pg_uuid_v81.0.0FUNCPostgreSQLC
IDExtensionBinLibLoadCreateTrustRelocSchema
4530pg_uuid_v8NoYesNoYesNoNopublic
Relateduuid-ossp pg_uuidv7 sequential_uuids pg_idkit pgx_ulid

Pinned to public so uuid operator commutators resolve on PostgreSQL 17 and 18.

Version

TypeRepoVersionPG VerPackageDeps
EXTPIGSTY1.0.01817161514pg_uuid_v8-
RPMPIGSTY1.0.01817161514pg_uuid_v8_$v-
DEBPIGSTY1.0.01817161514postgresql-$v-pg-uuid-v8-
OS / PGPG18PG17PG16PG15PG14
el8.x86_64
el8.aarch64
el9.x86_64
el9.aarch64
el10.x86_64
el10.aarch64
d12.x86_64
d12.aarch64
PIGSTY 1.0.0
PIGSTY 1.0.0
PIGSTY 1.0.0
PIGSTY 1.0.0
PIGSTY 1.0.0
d13.x86_64
PIGSTY 1.0.0
PIGSTY 1.0.0
PIGSTY 1.0.0
PIGSTY 1.0.0
PIGSTY 1.0.0
d13.aarch64
PIGSTY 1.0.0
PIGSTY 1.0.0
PIGSTY 1.0.0
PIGSTY 1.0.0
PIGSTY 1.0.0
u22.x86_64
PIGSTY 1.0.0
PIGSTY 1.0.0
PIGSTY 1.0.0
PIGSTY 1.0.0
PIGSTY 1.0.0
u22.aarch64
PIGSTY 1.0.0
PIGSTY 1.0.0
PIGSTY 1.0.0
PIGSTY 1.0.0
PIGSTY 1.0.0
u24.x86_64
PIGSTY 1.0.0
PIGSTY 1.0.0
PIGSTY 1.0.0
PIGSTY 1.0.0
PIGSTY 1.0.0
u24.aarch64
PIGSTY 1.0.0
PIGSTY 1.0.0
PIGSTY 1.0.0
PIGSTY 1.0.0
PIGSTY 1.0.0
u26.x86_64
u26.aarch64
PIGSTY 1.0.0
PIGSTY 1.0.0
PIGSTY 1.0.0
PIGSTY 1.0.0
PIGSTY 1.0.0

Build

You can build the RPM / DEB packages for pg_uuid_v8 using pig build:

pig build pkg pg_uuid_v8         # build RPM / DEB packages

Install

You can install pg_uuid_v8 directly. First, make sure the PGDG and PIGSTY repositories are added and enabled:

pig repo add pgsql -u          # Add repo and update cache

Install the extension using pig or apt/yum/dnf:

pig install pg_uuid_v8;          # Install for current active PG version
pig ext install -y pg_uuid_v8 -v 18  # PG 18
pig ext install -y pg_uuid_v8 -v 17  # PG 17
pig ext install -y pg_uuid_v8 -v 16  # PG 16
pig ext install -y pg_uuid_v8 -v 15  # PG 15
pig ext install -y pg_uuid_v8 -v 14  # PG 14
dnf install -y pg_uuid_v8_18       # PG 18
dnf install -y pg_uuid_v8_17       # PG 17
dnf install -y pg_uuid_v8_16       # PG 16
dnf install -y pg_uuid_v8_15       # PG 15
dnf install -y pg_uuid_v8_14       # PG 14
apt install -y postgresql-18-pg-uuid-v8   # PG 18
apt install -y postgresql-17-pg-uuid-v8   # PG 17
apt install -y postgresql-16-pg-uuid-v8   # PG 16
apt install -y postgresql-15-pg-uuid-v8   # PG 15
apt install -y postgresql-14-pg-uuid-v8   # PG 14

Create Extension:

CREATE EXTENSION pg_uuid_v8;

Usage

Sources: pg_uuid_v8 README, SQL definitions, control file.

pg_uuid_v8 generates UUIDs that look like UUID v4 values while embedding encrypted microsecond timestamps for extraction, sorting, and range predicates. The SQL file exposes both uuid_stego_* names and uuid_v8_* convenience aliases.

Generate UUIDs

CREATE EXTENSION pg_uuid_v8;

SELECT uuid_v8_set_seed('replace-with-a-secret-seed');
SELECT uuid_v8_generate();

The equivalent lower-level generator is:

SELECT uuid_stego_generate();

Use a default expression when inserting events:

CREATE TABLE events (
  id uuid PRIMARY KEY DEFAULT uuid_v8_generate(),
  data jsonb,
  created_at timestamptz DEFAULT now()
);

Extract And Query Hidden Timestamps

Extract the embedded timestamp as microseconds since the Unix epoch:

SELECT uuid_v8_extract_timestamp(id)
FROM events
ORDER BY uuid_v8_extract_timestamp(id)
LIMIT 10;

The README recommends functional indexes for time-based lookups:

CREATE INDEX events_uuid_v8_time_idx
ON events USING btree (uuid_v8_extract_timestamp(id));

SELECT *
FROM events
WHERE uuid_v8_extract_timestamp(id)
      BETWEEN timestamp_to_stego_time('2026-01-01'::timestamptz)
          AND timestamp_to_stego_time(now())
ORDER BY uuid_v8_extract_timestamp(id);

Helper functions convert between timestamps and the integer timestamp format:

SELECT timestamp_to_stego_time(now());
SELECT stego_time_to_timestamp(uuid_v8_extract_timestamp(id))
FROM events;

Range Helpers And Operators

The SQL definition includes direct range helpers:

SELECT *
FROM events
WHERE uuid_stego_in_range(
  id,
  now() - interval '24 hours',
  now()
);

It also defines timestamp-aware comparison functions and operators for uuid:

  • uuid_stego_compare(uuid, uuid) and uuid_v8_compare(uuid, uuid).
  • uuid_stego_lt, uuid_stego_le, uuid_stego_gt, uuid_stego_ge.
  • Operators <, <=, >, and >= compare UUIDs by hidden timestamp.

Seed And Encryption Mode

Set and inspect the seed:

SELECT uuid_v8_set_seed('replace-with-a-secret-seed');
SELECT uuid_v8_get_seed();

Available encryption modes are XOR, AES128, and AES256:

SELECT uuid_v8_get_encryption_mode();
SELECT uuid_v8_set_encryption_mode('AES128');
SELECT uuid_v8_set_encryption_mode('XOR');

For a persistent default, the README documents the uuid_v8.encryption_mode GUC:

ALTER SYSTEM SET uuid_v8.encryption_mode = 'AES128';
SELECT pg_reload_conf();

Caveats

  • Keep the seed secret; it is required to interpret hidden timestamps.
  • UUIDs generated with one seed and encryption mode must be decoded with the same settings.
  • Functional indexes on extracted timestamps add storage and update overhead, but are the intended path for efficient time-range predicates.
  • Local Pigsty metadata pins this extension to the public schema so the UUID comparison operator commutators resolve on PostgreSQL 17 and 18; test operators explicitly if using a different schema in a non-Pigsty build.