What UUID v7 Is and Why It Was Created
UUID v7 is a 128‑bit identifier defined in RFC 9562. Unlike its predecessor UUID v4, which is completely random, UUID v7 embeds a 48‑bit Unix millisecond timestamp at the beginning of the identifier. The remaining 80 bits are filled with cryptographically strong random data. The result is a 36‑character string (standard lowercase hexadecimal with hyphens) that, when sorted as plain text, sorts approximately by creation time.
The primary reason for v7’s existence is database index locality. UUID v4’s random layout causes random inserts in B‑tree indexes, leading to page splits and cache misses. A time‑sorted identifier like v7 inserts new rows close together in the index, dramatically improving write performance and reducing fragmentation. This was the key insight that led to the design of v7, and it is the single feature that makes this page valuable.
The generator on this page is specialised: it produces only UUID v7 (alongside sibling formats like v4, ULID, and NanoID, which are available via the format picker). When you select UUID v7, the tool uses the browser’s crypto.getRandomValues() to generate the random portion and injects the current system time as the timestamp. No data is sent to any server; the entire generation happens locally in your browser.
How the Generator Works – Inputs, Outputs, and Triggers
The page’s interface is minimal. You supply three inputs:
- Count: an integer between 1 and 100 inclusive.
- Uppercase: a toggle that switches the entire hexadecimal representation between lowercase and uppercase.
- Include hyphens: a toggle that includes or removes the four hyphens that normally separate the UUID’s time‑mid‑version‑variant sections.
The output is a list of generated UUID v7 identifiers. Below the list the page displays the current status: “Ready.” when idle, “Generated.” immediately after generation, and “Copied all!” when you click the “Copy All” button. You can also click any individual ID to copy that single string to your clipboard.
The critical rule is: changing any option immediately regenerates all IDs. The count text box has a change event (or equivalent) that fires as soon as you leave the field or press enter. The toggles trigger regeneration on each click. This ensures the output always reflects the current settings without a separate “generate” button.
The tool enforces the count range. Values below 1 are clamped to 1, values above 100 are clamped to 100. If you type a non‑numeric string, the input is invalid and the previous valid count is retained.
The Timestamp-Randomness Structure of UUID v7
A UUID v7 is composed of three parts when written in its canonical hex‑with‑hyphens form:
tttttttt-tttt-Vttt-Axxx-xxxxxxxxxxxx
- 48‑bit timestamp: the first 12 hex characters (6 bytes) represent the Unix epoch in milliseconds. This is a monotonically increasing value. For example, if you generate a v7 at Unix time 1,724,038,456,789 ms, the timestamp portion will be
0018F5A2B44D(hex). - Version bits: the 13th hex character (position 12, 0‑indexed) holds the version number. For UUID v7 this is always
7. - Variant bits: the 17th hex character (position 16) contains the variant field, which is binary
10xx– in hex this will always be8,9,A, orB. - Random bits: the remaining 62 bits (filling the rest of the 36‑character string) are filled with cryptographically random bytes.
When you toggle hyphens off, the tool removes the three hyphens, producing a 32‑character continuous hex string. Note that the version and variant bits remain preserved; only the visual grouping is removed. Toggling uppercase converts all hex letters (a–f) to uppercase, which is standard in many enterprise environments.
The timestamp is taken from Date.now() in milliseconds. Because JavaScript’s system time can be reset or skewed, the generator always uses the current time at the moment of generation – it does not cache or increment timestamps between generations within the same millisecond. This leads to a known limitation discussed below.
UUID v7 vs UUID v4 and Other Time-Based Identifiers
UUID v4 is a fully random 128‑bit identifier. Its 122 random bits (the remaining 6 bits are version/variant) produce 5.3×10³⁶ possible values – collision‑resistant for all practical purposes. However, random distribution means consecutive v4 IDs have no relation to each other. When used as primary keys in a B‑tree (the standard index structure in MySQL, PostgreSQL, and others), each insert goes to a random leaf page. Over time the index becomes heavily fragmented, and the buffer pool contains scattered pages instead of contiguous runs.
UUID v7 fixes this locality problem by prepending a timestamp. New IDs are generated with timestamps close to each other, so they cluster in the index. This can reduce insert‑time page splits by an order of magnitude, especially under high concurrency.
Other time‑based formats exist:
- ULID: 128 bits, Base32‑encoded, 26 characters. Also timestamp‑first with random suffix. ULID uses Crockford Base32, which avoids vowels to prevent accidental profanity.
- NanoID: not strictly a UUID; uses a configurable alphabet and length. Lacks a standard timestamp embedding.
- UUID v1: also timestamp‑based, but includes MAC address, posing privacy risks. UUID v1’s timestamp is in 100‑nanosecond intervals and uses a 60‑bit clock, making it unsuitable for many distributed systems.
UUID v7 strikes a balance: it uses a timestamp granular enough for real‑world ordering, keeps the 128‑bit structure that fits standard UUID columns, and relies on randomness rather than hardware identifiers.
Same-Millisecond Ordering and the Limits of Sortability
UUID v7 and ULID are sortable by creation time but do not guarantee strict ordering for IDs generated within the same millisecond. This is a common source of misunderstanding.
Because the timestamp portion is millisecond‑granular, all IDs created in the same clock tick will share the same timestamp. Their relative order is then determined by the random bits, which are not guaranteed to be monotonic. Two v7 IDs generated in the same JavaScript loop may appear in any order when sorted lexicographically.
Consider this example:
- ID A:
018f5a2b-44d7-7c00-a000-000000000001(timestamp 0x018f5a2b44d7, random suffixa000-000000000001) - ID B:
018f5a2b-44d7-7c00-a000-000000000002
Both have the same timestamp. They will sort by the random suffix: ...a0000000000001 before ...a0000000000002 in hex (since 1 < 2). But if the random bits are truly random, later IDs may have smaller random values. There is no built‑in monotonic counter for the random portion in v7.
This behaviour is by design. Strict ordering within the same millisecond would require a sequence number or lock, undermining parallelism. Distributed systems that need total order across nodes must embed a node ID and a counter in the random bits, which v7 does not standardise. For single‑machine usage where IDs are generated sequentially, the random portion is chaotic enough that out‑of‑order insertion is unlikely but not impossible.
The page’s generator does not attempt to increment a counter between calls within the same millisecond. Each call to the generation function produces a fresh timestamp and fresh random bytes. If you click “Generate” twice in the same clock tick, the second batch will share the same timestamp as the first, and the combined set of IDs may not be perfectly sorted.
Local Generation and Privacy – No Server Dependency
All generation happens inside the browser using crypto.getRandomValues(), which provides cryptographically secure random numbers. The tool does not send the count, the timestamp, or the generated IDs to any server. This means:
- No network latency – results appear instantly.
- No privacy exposure – even if the page’s backend were compromised, your generated IDs never leave your machine.
- Offline capability – the page’s JavaScript file is fully self-contained (assuming it has been loaded once).
The fact that the page is from BroBroGo is irrelevant to the generator’s operation. The tool could be saved as a local HTML file and still work. This is a deliberate design choice for developers who handle sensitive identifiers (e.g., for production databases) and cannot risk leakage.
The generation loop is trivial: for each ID, it computes a Date.now() timestamp, constructs a Uint8Array of 16 bytes, writes the 48‑bit timestamp into the first 6 bytes, sets the version (7) and variant bits according to RFC 9562, and fills the remaining bytes with random data. Then it formats the byte sequence into a hex string with optional hyphens and case conversion.
FAQ
1. Can I use UUID v7 as a primary key in PostgreSQL?
Yes, PostgreSQL natively supports UUID as a data type. You can store the 36‑character string or use the uuid type and rely on the B‑tree index. Some extensions like pg_uuidv7 provide server‑side generation, but client‑generated v7 identifiers work identically.
2. How many UUID v7 IDs can I generate per millisecond?
There is no enforced limit. The random 74‑bit suffix (after subtracting version/variant bits) gives about 1.8×10²² possible values per timestamp, so collisions are astronomically unlikely even under high concurrency. However, strict chronological ordering within the same millisecond is not guaranteed.
3. Does the generator support deterministic UUID v7 (e.g., with a fixed random seed)?
No. The tool always uses fresh random bytes from the browser’s cryptographic API. If you need deterministic sequences for testing, you would need to modify the source or use a separate utility.
4. Why does the output show “Ready.” before I generate anything?
The page generates a default set of IDs on first load (usually count=1). The status “Ready.” indicates the page is idle after initial generation. As soon as you change any option, the status reverts to “Generated.” after the new IDs appear.
5. What happens if I set count to 0 or negative?
The input is clamped: values below 1 are treated as 1, values above 100 are treated as 100. If you enter text that cannot be parsed as an integer, the previous valid count is retained.
6. Does UUID v7 guarantee uniqueness across different machines?
Yes, because the random 74 bits provide sufficient entropy (1.9×10²² possibilities). The timestamp adds an additional dimension, so IDs generated on different machines at different times are extremely unlikely to collide. No central coordination is needed.