UUID v7 and ULID Generator for PostgreSQL
This UUID v7 generator makes batches of time-ordered identifiers for Postgres primary keys, reads the timestamp back out of a value you paste in, and writes the SQL that makes one of them a column default. UUID v4 and ULID are here as well.
A batch of ten UUID v7 values appears here.
The same batch, in the shape a multi-row VALUES list takes.
Every value is made in this tab and nothing is sent anywhere. Ctrl or Cmd with Enter draws another batch.
What it does and how to use it
Pick a type and a batch size, press Generate, then copy the block. Beside it the same batch sits wrapped in quotes and parentheses, the shape a multi-row VALUES list wants, with a copy button of its own.
Paste a value into Decode and it reports the version, the two variant bits that mark it as RFC 9562 and, where the format carries a timestamp, the creation time written both as ISO 8601 and as Unix milliseconds, which is the number to compare against a created_at column when you are checking whether a backfill kept its order. A v4 comes back with no time at all, because it has none to give.
Under SQL sits an INSERT built from the batch on screen, next to five table definitions covering the built-in functions and the two extensions. The decoder has no button because the reading follows what you paste, and on the Generate tab Ctrl or Cmd with Enter draws a fresh batch.
gen_random_uuid vs uuid_generate_v4, and where v7 fits
gen_random_uuid() has been in core since PostgreSQL 13, whose release note records that UUID generation had until then lived only in the uuid-ossp and pgcrypto modules. That history is behind the question people keep landing on, where the extension is installed and uuid_generate_v4() still fails. CREATE EXTENSION loads into the current database only, and an unqualified call is resolved through search_path, so a function sitting in an extensions schema stays invisible until you qualify it or put that schema on the path.
select uuid_generate_v4();
-- ERROR: function uuid_generate_v4() does not exist
select extensions.uuid_generate_v4(); -- resolves
show search_path; -- "$user", public
What separates v7 from v4 is the leading 48 bits, which hold a Unix millisecond count. Values made one after another therefore sort in that order, and a B-tree primary key index takes them as appends at one edge instead of as writes landing anywhere in the tree. How much that buys depends on the write volume of the table, which is why this page quotes no benchmark.
ULID encodes the same idea as 26 Crockford base32 characters. Postgres has no ULID type, so those characters live in text or char(26), while a v7 fits the 16 bytes a uuid column already spends. On 18 the server generates v7 itself through uuidv7(), which takes an optional shift interval, alongside an explicit uuidv4() alias; uuid_extract_timestamp() and uuid_extract_version() arrived one release earlier, and the first returns null for anything that is not version 1 or 7.
Frequently asked questions
Batches of one, ten or a hundred values in three formats, UUID v4, UUID v7 and ULID. The decoder reads a value you paste and reports its version, its variant bits and, for v7 and ULID, the millisecond it was made. The SQL tab turns the current batch into an INSERT and lists the table definitions that make the server produce such values instead.
Both are 128 bits, and with both the odds of a collision are not something you plan around. A v4 is random throughout, so consecutive values land in unrelated places in an index. A v7 opens with a 48-bit millisecond timestamp, which keeps values made in the same period next to each other and lets ordering by the key stand in for ordering by creation time.
Its own documentation says the module is only necessary for requirements beyond what core PostgreSQL offers. gen_random_uuid() has been built in since 13 and uuidv7() since 18, so a new schema rarely reaches for uuid_generate_v4(). When that call fails although the extension is installed, check which database it was created in and whether its schema is on your search_path.
Generate the value in the application, which is what this page does, or install the pg_uuidv7 extension, whose README covers PostgreSQL 13 through 18 and adds uuid_generate_v7(). Writing a small SQL function that assembles the bytes is a third route. The built-in uuidv7() exists only from PostgreSQL 18 onward.
Across milliseconds they do, because the first ten characters are the timestamp. Inside a single millisecond the answer depends on the generator. The reference implementation re-randomises the tail on every call, and in a check on 2026-09-11 a batch of twenty came back out of order in all two hundred runs, so this page uses the monotonic variant, which increments the tail and keeps a copied batch in the order it was made.
It is free and there is nothing to sign up for. Two MIT-licensed libraries do the work inside your tab, so there is no per-use cost on our side to recover.
Nothing leaves it. Values are made and read in JavaScript inside the page, and neither what you paste nor what you generate is sent anywhere. The site does count that the tool was used, and that count carries the name of the tool and nothing else.
Those values fill one column, and rows that point at each other need the same identifier in both places, which is the part a generator on its own cannot do for you. The guide below walks through pointing Seedfast at a database and having it write the rows.
Other free PostgreSQL tools
- PlaygroundA real Postgres server compiled to WebAssembly, running inside the tab. Create tables, insert rows, join them, and read the plan, with no server behind it.
- Password hash generatorTurns a password into the verifier string Postgres stores, in the SCRAM-SHA-256 format CREATE ROLE accepts, plus the legacy md5 form and a bcrypt hash for Supabase auth rows.
Further reading: What is referential integrity? Definition and examples.