Complete reference for the native uuid type, gen_random_uuid(), the uuid-ossp extension, and UUID v7 support in PostgreSQL 18 — plus indexing considerations for UUID primary keys.
Quick Start
Generate a Random UUID (v4) with gen_random_uuid()
PostgreSQL 13+ includes gen_random_uuid() built into core — no extension required:
Older tutorials show uuid_generate_v4() from the uuid-ossp extension. Since PostgreSQL 13, gen_random_uuid() is built into core (via pgcrypto internals) and needs no CREATE EXTENSION statement at all.
Native Type
The Native uuid Column Type
PostgreSQL has a dedicated 16-byte uuid type — use it instead of VARCHAR(36) for both storage efficiency and built-in format validation:
SQL — table with UUID primary key
CREATE TABLE orders (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
customer_name TEXT NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW()
);
Storage Type
Size
Validates Format
UUID (native)
16 bytes
Yes — rejects malformed input at insert time
VARCHAR(36)
36+ bytes
No — accepts any string
CHAR(32) (no hyphens)
32 bytes
No — accepts any string
UUID v7
UUID v7 in PostgreSQL 18
PostgreSQL 18 (released 2026) added native uuidv7() support — time-ordered UUIDs that solve the index fragmentation problem of random v4 keys:
B-tree indexes perform best with roughly ascending insert order. Random UUID v4 causes page splits and index bloat at scale. UUID v7’s timestamp prefix keeps new rows clustered together in the index — matching the performance profile of a SERIAL column while keeping UUID’s distributed-generation benefits.
⚠️
Check your PostgreSQL version first
uuidv7() requires PostgreSQL 18 or later. On older versions, use the pg_uuidv7 extension, or generate v7 UUIDs in your application code (see our Python or JavaScript guides) and insert them as regular UUID values.
Legacy Extension
uuid-ossp Extension (Pre-PostgreSQL 13)
If you’re on an older PostgreSQL version, install the uuid-ossp extension for UUID generation functions:
SQL
CREATE EXTENSION IF NOT EXISTS “uuid-ossp”;
SELECT uuid_generate_v4(); — random UUID
SELECT uuid_generate_v1(); — time-based UUID
SELECT uuid_generate_v5(uuid_ns_dns(), ‘example.com’); — deterministic
Validation & Bulk
Validating and Bulk-Generating UUIDs
SQL — validate a UUID string
— Casting to uuid validates automatically
SELECT ‘550e8400-e29b-41d4-a716-446655440000’::uuid; — OK
SELECT ‘not-a-uuid’::uuid; — ERROR: invalid input syntax for type uuid
SQL — safe validation function
CREATE OR REPLACE FUNCTION is_valid_uuid(val TEXT) RETURNS BOOLEAN AS $$
BEGIN
PERFORM val::uuid;
RETURN TRUE;
EXCEPTION WHEN invalid_text_representation THEN
RETURN FALSE;
END;
$$ LANGUAGE plpgsql;
SQL — bulk generate 10,000 rows
INSERT INTO orders (id, customer_name)
SELECT gen_random_uuid(), ‘Test Customer ‘ || n
FROM generate_series(1, 10000) n;
FAQ
PostgreSQL UUID FAQ
No, not since PostgreSQL 13. The gen_random_uuid() function is built into core and requires no CREATE EXTENSION statement. Only older PostgreSQL versions (12 and earlier) need the uuid-ossp extension installed for UUID generation functions like uuid_generate_v4().
Use UUID v7 (via uuidv7() in PostgreSQL 18+) if you need distributed generation across multiple servers without coordination, or want to avoid exposing row counts. Use SERIAL/BIGSERIAL if you only need a single-database auto-increment and want the smallest possible index size. Avoid random UUID v4 as a primary key at scale, since it causes B-tree index fragmentation — v7 solves this by being time-ordered.
PostgreSQL 18, released in 2026, added the native uuidv7() function. For earlier versions, you can use the third-party pg_uuidv7 extension, or generate UUID v7 values in your application code and insert them as regular UUID column values.
Yes. Casting any string to the uuid type, such as ‘value’::uuid, validates the format immediately and raises an invalid_text_representation error if it does not match the RFC 4122/9562 pattern. This is a key advantage over storing UUIDs as VARCHAR, which accepts any string without validation.