Try it here
Generate a UUID to paste into your PostgreSQL code, in any version and format.
Your UUIDs
Copy one, copy them all, or download the list. The format options above apply to everything shown here.
Random v4: gen_random_uuid
SELECT gen_random_uuid();
-- f47ac10b-58cc-4372-a567-0e02b2c3d479
CREATE TABLE orders (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
status text NOT NULL
);
gen_random_uuid() is built into PostgreSQL 13 and newer, no extension needed. Before 13 it came from the pgcrypto extension.
Time ordered v7: uuidv7 on PostgreSQL 18
SELECT uuidv7();
SELECT uuidv4(); -- alias for gen_random_uuid, also new in 18
CREATE TABLE events (
id uuid PRIMARY KEY DEFAULT uuidv7(),
payload jsonb
);
SELECT uuid_extract_timestamp(id) FROM events; -- the creation time, from v1 or v7
SELECT uuid_extract_version(id) FROM events; -- 7
PostgreSQL 18, released in September 2025, added native v7 generation. Rows inserted later get larger ids, so the primary key index grows at one end instead of everywhere, the same benefit a bigserial has. If you are on 17 or older, either generate v7 in the application, see our Python, Go and Java pages, or install the pg_uuidv7 extension. A plain SQL function also works:
-- v7 for PostgreSQL 13 to 17, no extension
CREATE FUNCTION uuid_v7() RETURNS uuid LANGUAGE sql VOLATILE AS $$
SELECT encode(
set_bit(set_bit(
overlay(uuid_send(gen_random_uuid()) placing
substring(int8send((extract(epoch FROM clock_timestamp()) * 1000)::bigint) FROM 3)
FROM 1 FOR 6),
52, 1), 53, 1),
'hex')::uuid;
$$;
v1, v3 and v5: the uuid-ossp extension
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
SELECT uuid_generate_v1(); -- time based
SELECT uuid_generate_v4(); -- same as gen_random_uuid
SELECT uuid_generate_v5(uuid_ns_dns(), 'example.com'); -- name based, deterministic
SELECT uuid_nil();
Validate and cast
SELECT 'f47ac10b-58cc-4372-a567-0e02b2c3d479'::uuid; -- ok
SELECT 'not-a-uuid'::uuid; -- ERROR: invalid input syntax for type uuid
-- uppercase, braces and no hyphens are all accepted on input
SELECT '{F47AC10B-58CC-4372-A567-0E02B2C3D479}'::uuid;
-- check without raising, PostgreSQL 16+
SELECT pg_input_is_valid('not-a-uuid', 'uuid'); -- false
Use the uuid type, not text
A uuid column is 16 bytes. The same value as text or varchar(36) is 37 bytes plus overhead, indexes are more than twice as large, and comparisons are slower because they go character by character. The uuid type also validates on write, so junk never gets in. Every driver maps it to the language's native type: uuid.UUID in Python, UUID in Java, uuid.UUID in Go, Guid in .NET.
Mistakes to avoid
- Random v4 keys on very large, write heavy tables. Works, but v7 keeps the index and the cache far healthier. The primary key post has numbers.
- ORDER BY id expecting creation order. Only true for v7 or v6. With v4, order by a timestamp column.
- md5(random()::text)::uuid. An old trick from before gen_random_uuid. The version bits are wrong and the randomness is weak.
Frequently asked questions
Does PostgreSQL have a built in UUID generator?
Yes. gen_random_uuid() for v4 since PostgreSQL 13, and uuidv7() plus uuidv4() since PostgreSQL 18. Older versions need pgcrypto or uuid-ossp.
How do I generate UUID v7 in PostgreSQL before version 18?
Generate in the application, install the pg_uuidv7 extension, or create the small SQL function shown above, which builds a v7 from clock_timestamp and gen_random_uuid.
Should the primary key be uuid or bigserial?
bigserial is smaller and faster if ids never leave the database and there is one writer. uuid is better when ids are created by clients, exposed in URLs, or merged from several sources. With v7 the performance gap is small.