UUID Generator

Version 4 identifiers in bulk, with the casing and braces you actually need.

Batch

            

In this batch
Random bits
Chance of a repeat

The nil UUID

All 128 bits zero, defined by the standard as the value that means no value at all. Databases and APIs that dislike a null in a unique column use it as a sentinel. It is a valid identifier and a useless one, since everything that needs a placeholder will produce the same string.

Batch

25
Around each value

Quotes and commas give you the body of a JSON array: every line quoted, every line but the last followed by a comma. Paste the block between [ and ] and it parses.

Shape

Good practice

  • Let the database store 16 bytes. PostgreSQL has uuid, MySQL has BINARY(16). A 36-character string costs more than twice the space and compares more slowly.
  • Never generate one as a fallback. If the random source is unavailable, fail loudly instead of carrying on with a weaker value.
  • Normalise before comparing. The same identifier in uppercase and in braces is the same identifier, and a text column will treat it as two.
  • Paste, don't retype. Transposing two characters in a v4 UUID gives you another perfectly valid UUID that points at nothing.

Random is not the same as secret. No one will guess another identifier from yours, which is why a v4 UUID makes a decent reset link. It is still a bearer value: whoever reads it can use it, so a token that grants access wants a short expiry, a single use, and a hash in the database rather than the string itself.

Sixteen bytes, printed as thirty-six characters

The value is 128 bits. The string everyone calls a UUID is one way of writing those bits down, and the hyphens in it carry no data at all — they group the hex into 8-4-4-4-12 because a solid run of 32 characters is harder to read aloud and harder to compare by eye. Four characters of that string are decoration, which is worth knowing before a column is sized:

f47ac10b - 58cc - 4372 - a567 - 0e02b2c3d479
      └──────┘   └──┘   └──┘   └──┘   └──────────┘
        32 bits  16     16      16         48

        4372  the leading 4 is the version field
        a567  the leading a is the variant field

        128 bits of value, 36 characters of text
        the same value in base64:  22 characters, no hyphens

Stored as text, a UUID wants 36 characters and a fixed-width column, and the case is a decision you have to make once and apply everywhere: a comparison between an uppercase and a lowercase spelling is a comparison between two different strings. Stored as bytes, the same value takes 16, the database can index it properly, and the formatting question disappears because nothing prints it until something needs to read it.

The hyphens are not part of the identity. Every parser accepts the string with them, most accept it without, and several accept a braced or a urn:uuid: form of the same bytes. What is not safe is trimming for width: eleven characters removed from the end leaves a value with fewer bits than the one it came from, and two identifiers that were distinct can become the same string. A column that is too narrow is a sizing problem, and the answer is a binary type rather than a shorter string.

Unique is not ordered

A database keeps its rows in a structure sorted by the primary key, and an index on a random key pays for that in every insert. A counter appends at the end, where the next free page already is. A random value lands somewhere in the middle of the tree, so the page it needs is probably not in memory, a read has to happen before the write, and the pages that do get cached are spread across the whole index instead of clustered at one end.

Whether that matters is a question about the shape of the table rather than about size. A table with a few thousand rows and modest write rates will not notice, and the convenience of any client inventing its own identifier without asking the database first is worth more than the index ever costs. A table taking thousands of inserts a second notices immediately, and the usual fix is an identifier whose leading bits come first in time — a version that puts a timestamp where the index can use it, keeping the randomness after it.

There is a second cost that has nothing to do with performance: a random key sorts arbitrarily, so it can never be used to page through records in the order they were created or to shard them by range. Whatever the key is made of becomes the only ordering the table has, and choosing it is choosing that.

The same name should give the same id

A random identifier is a name for an event, not for a thing. Run an import twice and the rows get two different identifiers, so the second run duplicates everything the first one wrote. A deterministic version solves it by taking the thing's natural key — a URL, an email address, a path — and hashing it together with a namespace value. Same input, same identifier, on any machine, in any process, forever.

The namespace is what keeps two kinds of thing apart. Hashing a bare URL would give the same value as hashing any other string that happened to be identical, so the namespace says which family the name belongs to, and two families that both contain the string /index produce different identifiers. The standard publishes a handful of namespaces for the obvious cases and expects you to invent your own for your own data.

It is not a security boundary, and it is not a secret. Anyone who knows the namespace and the name can compute the identifier, which is the point — it is a way of agreeing on a name without coordinating, not a way of hiding one. Where the identifier does have to be unguessable, a random draw is the right tool and this one is the wrong one.

What actually goes wrong

Duplicates almost never come from the randomness. They come from a column sized for 36 characters when something upstream wrote 32, from a truncation somewhere in a pipeline, from a case-insensitive collation on one side and a case-sensitive one on the other, or from a client generating identifiers with a seeded generator that produces the same sequence on every run. A collision report is worth reading as a plumbing bug until something proves otherwise.

The other failure to avoid is choosing a version that publishes something you did not mean to publish. A version built from a host address and a timestamp embeds a hardware identifier and the moment of creation, both of which survive into any document or URL the identifier is pasted into. Those are the versions to read and not to make.

Two nearby tools cover what this one does not. A Hash Generator produces a digest of bytes, which answers a different question in a similar-looking length, and the Password Generator is where an unguessable string belongs — an identifier is a name, and a name that grants access needs an expiry, a single use, and a hashed record rather than the string itself.

Reference

Which version to generate, and when it matters

VersionHow the bits are madeCarries a MAC or timestampWhere you meet it
v1The MAC address of the host, a 60-bit timestamp and a clock sequenceYesLegacy systems. Modern libraries read it and few will make one
v2A timestamp with its low bits replaced by a POSIX user or group id, for DCE securityYesNowhere much. Specified by the standard, generated by almost nothing
v3MD5 of a namespace UUID and a name, cut to 128 bitsNoOlder deterministic schemes, still parsed widely
v4122 bits from the platform's cryptographic random sourceNoMost APIs, most client libraries, and every identifier this page draws
v5SHA-1 of a namespace UUID and a name, cut to 128 bitsNoIdempotent imports, content-addressed ids and cache keys
v6The v1 timestamp, reordered so the high bits come firstYesNewer database and library support
v7A 48-bit Unix millisecond timestamp in the leading bits, then 74 random bitsYesDatabase primary keys and log correlation
nilAll 128 bits zeroNoA placeholder where a unique column will not take a null
maxAll 128 bits oneNoAn upper bound in range comparisons

What a version embeds decides where it is safe to use, so the right-hand columns are the ones to read first. Nothing in the list is a better identifier in the abstract: a version is either the right shape for the job or it is not.

v3 and v5 are deterministic. Give either one the same namespace and the same name and it returns the same identifier, on any machine, every time. That is what makes v5 the right answer for an idempotent import, where the same file run twice must not duplicate rows, and for a content-addressed id that has to survive a rebuild.

v4 is what almost everyone means by the word, and it is what this page draws: 122 random bits, with the version nibble and the variant bits reserved. A repeat needs on the order of two to the power of 61 draws before it becomes likely, which nobody reaches. Unique is not the same as ordered, though: random keys land anywhere in the index, so an insert-heavy table scatters its writes instead of appending them. v7 exists for exactly that, putting a Unix millisecond timestamp in the leading bits so identifiers arrive in creation order and still cannot be guessed.

v1 is the one to avoid: it embeds the MAC address of the machine that made it and the moment it was made, a hardware identifier you did not mean to publish. v2 was specified for DCE and is abandoned in practice. nil and max are fixed all-zero and all-one strings, useful as sentinels and useless as identifiers.

Questions

Identifiers, answered plainly

Can two v4 UUIDs collide?

In theory yes, because the space is finite and the draw is random. In practice the numbers are absurd: about 2.3 quintillion identifiers before the chance of some repeat reaches one in two. What actually produces duplicates is a broken random source, a column too short for 36 characters, or a client that generates identifiers with a seeded pseudo-random generator instead of the platform one.

Why is the thirteenth character always a 4?

Because the four bits at that position are the version field, and 4 means randomly generated. The seventeenth character is the variant field: it is always 8, 9, a or b, which is the pattern the RFC reserves for identifiers generated this way. Those six bits are not random, so a v4 UUID carries 122 bits of randomness rather than the 128 its length suggests.

Should I use v4 as a database primary key?

It works, and it lets any client invent an identifier without asking the database first, which is worth a lot in a distributed system. The cost is index locality: random keys scatter inserts instead of appending them. If you need both, a v7 puts the timestamp first and keeps the randomness, and this generator deliberately makes v4 only, so it will not quietly hand you something that sorts.

Is a UUID a good password reset token?

A v4 is strong enough that guessing one is hopeless, which is the part people worry about. The part they forget is everything after it: one use, a short expiry, bound to the account that requested it, and stored as a hash rather than a plain string, so that a leaked database backup is not a list of live reset links.

What is the nil UUID for?

It is 128 zero bits, and the standard defines it as the value meaning no value. Systems that dislike a null in a unique column use it as a placeholder, and some test suites use it as a known-bad identifier. It parses like any other UUID and identifies nothing in particular, since everything that needs a placeholder produces the same one.

Is anything sent while the batch is drawn?

Nothing is uploaded and nothing is sent. The bits come from the browser's cryptographic random source, which asks the operating system rather than a network service, and a batch of 500 is filled in one call. Open a network panel, draw a batch, and watch it record no requests at all.

Is a UUID the same as a GUID?

In practice yes, and the difference is a naming habit rather than a format. GUID is Microsoft's word for the same 128-bit value, printed uppercase and often wrapped in braces by Windows tooling. Microsoft's documentation and the RFC describe the version fields slightly differently, and .NET stores a GUID's first bytes in its own order, so a comparison that behaves in one language can surprise you in another. Every parser accepts either spelling, and a v4 GUID is the same sixteen bytes as a v4 UUID.

Can I shorten a UUID to save space?

You can re-encode it, which is a different move from cutting characters off. The 16 bytes fit in a 22-character base64 string or a 26-character base32 one, both shorter than the 36-character hyphenated hex, and no bits are lost. Truncation is the version that breaks things: a UUID with characters removed has less entropy than the one it came from and starts colliding far sooner. If a column is too narrow, the fix is a 16-byte binary type, not a shorter string.

Why is the UUID in my logs different every time I restart?

Because a v4 is drawn fresh on every call, so a new process start gets a new value and nothing links it to the run before. If that identifier is meant to name a thing rather than an event, a random value is the wrong tool: there is nothing to look it up by once the process that made it has exited. Feed the same namespace and name through v5 and the same input gives the same identifier after a restart, a redeploy, or on another machine. This generator draws v4 only, so an id that has to survive a restart needs a hash of the input rather than a fresh draw.