PostgreSQL generates UUIDs through the built-in gen_random_uuid() function, which returns a version 4 UUID as defined by RFC 4122 and updated by RFC 9562, with no extension installation required on PostgreSQL 13 or later. The function draws 122 random bits from a cryptographically secure source on the server, fixes the version and variant bits to match the spec, and returns the canonical 8-4-4-4-12 hex string such as f47ac10b-58cc-4372-a567-0e02b2c3d479. The same shape is accepted by the native uuid column type, so the result can be stored directly without casting or transformation. Two paths exist: the built-in functions (gen_random_uuid() and the alias uuidv4()) and the older uuid-ossp contrib module, which adds uuid_generate_v1, uuid_generate_v4, uuid_generate_v5, and a few related calls. New applications should use the built-in random function as the default because it is always available, requires no CREATE EXTENSION, and produces the same kind of identifier that the rest of the modern web stack already speaks. This guide walks through both paths, shows how to set the function as a column DEFAULT so inserts need not supply a value, and explains when generating UUIDs outside the database is the cleaner choice.

Two Paths to Generate a UUID in PostgreSQL
PostgreSQL exposes UUID generation through two surfaces. The first is the pair of built-in functions that ship with the server itself and need no installation; the second is a contrib module called uuid-ossp that adds older algorithm-specific calls and remains useful on releases before PostgreSQL 13. The built-in functions are the recommended default for new work because they are always available, do not require superuser privileges to enable, and produce identifiers that match what every other language and library calls "a UUID".
| Method | Function | Output | Setup | PostgreSQL versions |
|---|---|---|---|---|
| Built-in | gen_random_uuid() | Version 4 UUID (random) | None | 13 and later |
| Built-in alias | uuidv4() | Version 4 UUID (random) | None | 13 and later |
| uuid-ossp | uuid_generate_v4() | Version 4 UUID (random) | CREATE EXTENSION uuid-ossp | All supported |
| uuid-ossp | uuid_generate_v1() | Version 1 UUID (time + MAC) | CREATE EXTENSION uuid-ossp | All supported |
| uuid-ossp | uuid_generate_v5(namespace, name) | Version 5 UUID (SHA-1 namespace) | CREATE EXTENSION uuid-ossp | All supported |
The two random variants — gen_random_uuid() and uuid_generate_v4() — produce the same shape: 32 hex digits with the version nibble set to 4 and the variant nibble set to 8, 9, a, or b. They differ only in how they reach that shape, since one is always available and the other requires installing the contrib module.
Use gen_random_uuid() in SQL
The built-in function is callable anywhere a value expression is allowed: in a SELECT, inside an INSERT, as part of a DEFAULT, or in a RETURNING clause. The following steps cover the common cases.
- Confirm your server is PostgreSQL 13 or later by running SELECT version(); in psql or your client of choice.
- Generate a single UUID to see the canonical form: SELECT gen_random_uuid();. The result is a hyphenated lowercase string with 32 hex digits, for example f47ac10b-58cc-4372-a567-0e02b2c3d479.
- Insert the value into a uuid column by passing the function call where a value would normally go: INSERT INTO devices (id, name) VALUES (gen_random_uuid(), 'sensor-01');.
- Cast a string literal to uuid if you already have a value to load: INSERT INTO devices (id, name) VALUES ('f47ac10b-58cc-4372-a567-0e02b2c3d479'::uuid, 'sensor-01');.
- Use the function in a DEFAULT clause or generated column so every new row gets a value automatically, without changing the application code that issues the insert.
For bulk generation, repeat the call inside a generate_series. The following query returns 10 fresh UUIDs in one round trip: SELECT gen_random_uuid() FROM generate_series(1, 10);. The same approach scales to any size you need and stays inside the database.
Enable uuid-ossp on Older PostgreSQL Versions
Servers running PostgreSQL 12 or older do not include gen_random_uuid() in the core distribution, and deployments that need version 1 (timestamp plus MAC), version 3, or version 5 identifiers rely on the uuid-ossp contrib module. Install it once per database with CREATE EXTENSION, then call the function that matches the version you want.
CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; SELECT uuid_generate_v4();
The extension exposes uuid_generate_v1(), uuid_generate_v1mc(), uuid_generate_v3(), uuid_generate_v4(), and uuid_generate_v5(). uuid_generate_v4() is the closest equivalent to gen_random_uuid() and is the right choice for general primary keys. uuid_generate_v1() produces time-ordered identifiers that embed a timestamp and the host's MAC address, which can leak network information and so is rarely the right default for new work. uuid_generate_v5() is deterministic given a namespace UUID and a name string, which makes it useful for IDs that must be reproducible across systems.
If the extension fails to install with a "could not open extension control file" error, the contrib package is missing from the server install. On Debian and Ubuntu that is postgresql-contrib; on RHEL and derivatives the matching postgresql-contrib RPM. After the package is in place, CREATE EXTENSION works without restarting the server.
Set a Generated UUID as a Primary Key DEFAULT
The most common reason to reach for gen_random_uuid() is to populate a primary key column without forcing every insert to mint the identifier. PostgreSQL lets you wire the function into the column definition so the database assigns the value automatically.
CREATE TABLE orders ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), customer_email text NOT NULL, created_at timestamptz NOT NULL DEFAULT now() ); INSERT INTO orders (customer_email) VALUES ('[email protected]');
The INSERT never names the id column, yet the resulting row carries a freshly generated version 4 UUID. The pattern works for any uuid column that should always carry a value, including foreign key columns that need to be filled in by the database rather than by the client. If time-ordered keys are required for B-tree locality, the newer uuidv7() function available in recent PostgreSQL releases and contrib modules produces sortable identifiers while keeping the same column type.
An uuid primary key is wider than a 4-byte serial or 8-byte bigserial, so indexes grow accordingly. For most workloads the trade is worth it: random keys let you generate IDs on the client, merge replicas without key collisions, and avoid leaking record counts through predictable sequences. Composite primary keys that combine a UUID with a tenant identifier follow the same DEFAULT pattern.
Generate UUIDs Outside PostgreSQL for Tests and Migrations
Some tasks need UUID values before they reach the database — fixture files, seed scripts, mock APIs, or staging data loaded through COPY. Generating them in the application layer or in a browser keeps the database out of the loop and lets you preview the exact text that will land in the column.
A practical approach is to use the UUID Generator, which produces 1 to 100 RFC 4122 v4 UUIDs at a time using the browser's crypto.getRandomValues CSPRNG. The 13th hex digit of every output is 4 and the 17th is 8, 9, a, or b, so the strings are structurally identical to what gen_random_uuid() returns. You can toggle uppercase or strip the hyphens to match your column's expected text form, then paste the values directly into a .sql file or a COPY payload without leaving the editor.
This is also a safe way to seed identifiers that should not appear in logs or analytics: every value is generated locally in the browser tab, with no server round-trip, so the strings can go straight into version-controlled fixtures without exposing internal IDs to a remote service. For one-off test data the workflow is fast — pick a count, click once, copy once — and it scales to 100 UUIDs at a time when a wider batch is needed.
UUID Versions and Why gen_random_uuid() Is Random
A UUID is a 128-bit label written as 32 hex digits in a canonical 8-4-4-4-12 pattern. Of those 128 bits, six are fixed by the spec: four encode the version (so the 13th hex digit is always 4 for a version 4 UUID) and two encode the variant (so the 17th hex digit is always 8, 9, a, or b). The remaining 122 bits are where version-specific data lives, and for version 4 that data is pure randomness.
| UUID version | How the bits are derived | Typical use |
|---|---|---|
| 1 | 60-bit timestamp + MAC address (or random node) | Legacy systems that want sortable IDs |
| 3 | MD5 hash of namespace + name | Deterministic IDs from a known name (legacy) |
| 4 | 122 random bits | Default for new applications (gen_random_uuid) |
| 5 | SHA-1 hash of namespace + name | Deterministic IDs (preferred over v3) |
| 7 | 48-bit millisecond timestamp + random tail | Sortable IDs with B-tree locality |
The 122 random bits give 2^122 ≈ 5.3 × 10^36 possible UUIDs, which is why version 4 is treated as effectively collision-free in practice. The full set of rules and fixed bits is defined in RFC 4122 and its 2024 replacement RFC 9562, the documents that gen_random_uuid() conforms to. Version 4 is the right default for most PostgreSQL primary keys because the identifiers need no clock, no MAC address, and no namespace: they are unguessable and statistically independent, which is exactly what the spec promises for the "unique without coordination" guarantee.