UUID Generator

Generate v4 or time-ordered v7 UUIDs, and inspect any UUID you already have.

5

Random UUIDs

    Inspect a UUID

    Paste one to see which version it is and what, if anything, it has embedded in it.

    The versions, and which two matter

    There are eight, and for new work the choice is really between two. The rest are worth recognising when you meet one in an old system.

    VersionBuilt fromUse it when
    v4122 random bitsYou need unguessable. The default for tokens and identifiers.
    v7Timestamp + randomnessYou need a database key. Sorts by creation time.
    v1Timestamp + MAC addressLegacy. Leaks the machine and the time.
    v3 / v5Hash of a namespace and nameYou need the same input to always give the same ID.
    v6v1, reorderedMigrating v1 data and wanting it to sort.
    v8Whatever you decideAlmost never.

    The index problem, which is the real reason v7 exists

    This is the practical argument and it is worth understanding rather than taking on faith.

    A database primary key is stored in a B-tree, ordered. Insert sequential integers and every new row lands at the right-hand edge: one page stays hot in memory, the tree grows tidily, and writes are cheap.

    Insert v4 UUIDs and every row lands somewhere random. Pages all over the tree are touched, each one has to be read before it can be written, and pages split as they fill. On a table of any size, insert throughput drops noticeably and the index fragments — the effect is well documented and is why UUID keys got their reputation.

    v7 fixes it by putting the timestamp first. Generate a handful above with v7 selected and look at the shared prefix: values created close together are adjacent, so inserts append at the end of the index like an integer while remaining globally unique. You keep the property that made UUIDs attractive — generate an ID anywhere, with no coordination — without paying for it on every write.

    Precisely: ordering is guaranteed between milliseconds, not within one. Two v7 UUIDs generated in the same millisecond are ordered by their random tails, which RFC 9562 permits and optionally allows implementations to tighten with a counter. It makes no difference to the index-locality argument, which only depends on the leading timestamp.

    The cost that remains for both: 16 bytes against 4 or 8, replicated into every index that references the key. On a large table with several foreign keys, that is real disk.

    What v7 discloses

    The timestamp is readable by anyone holding the identifier. Paste a v7 UUID into the inspector above and it will tell you the millisecond it was created.

    Usually harmless. Occasionally not: a v7 identifier in a public URL reveals when a record was created, which can be enough to infer sign-up rates, order volumes, or that a document was back-dated. If that matters, v4 for anything user-visible and v7 for internal keys is the straightforward split.

    Where the randomness has to be real

    The collision arithmetic everyone quotes — 2.7 quintillion before a coin-flip chance of one collision — assumes 122 genuinely random bits. It is a statement about the format, not about your implementation.

    A UUID built on Math.random() has neither the entropy nor the unpredictability the number implies, and collisions in the wild have essentially always been this rather than bad luck. Two processes started in the same second with the same seed produce the same sequence.

    This page uses crypto.randomUUID() where it exists and crypto.getRandomValues otherwise. Worth checking whatever your own code uses, particularly if UUIDs are standing in for tokens — a predictable password-reset identifier is a full account takeover.

    Storing them efficiently

    The 36-character text form is convenient and wasteful. The alternatives, all the same 128 bits:

    • Native UUID type — Postgres has one, and it stores 16 bytes. Use it.
    • BINARY(16) — the MySQL equivalent, roughly half the storage of CHAR(36).
    • Base64 — 22 characters, when it has to be text and length matters.
    • Base32 — 26 characters, case-insensitive, which is what you want if a human will ever read one aloud.

    Related

    For secrets a person has to type rather than a machine has to store, the password generator uses the same random source. To read the timestamp out of a v7 UUID in another format, the timestamp converter takes it from there.

    UUID questions

    Can two UUIDs collide?

    In principle yes; in practice no, provided the randomness is real. A v4 UUID has 122 random bits, and you would need to generate about 2.7 quintillion of them before reaching a 50% chance of a single collision — roughly a billion per second for 85 years. The realistic failure is never the mathematics: it is a weak random source. A UUID built on Math.random() or on a poorly seeded PRNG can and does collide, which is why this page uses the browser's cryptographic source.

    Should I use a UUID as a database primary key?

    It depends on the version, and the difference is large. A v4 UUID is random, so consecutive inserts land at random points in a B-tree index — pages split, the index fragments, and write throughput drops measurably on a large table. A v7 UUID starts with a millisecond timestamp, so inserts append at the end like an auto-increment integer while keeping global uniqueness. If you want UUID keys, use v7. The other cost applies to both: 16 bytes against 4 or 8 for an integer, on every index that references it.

    What is UUID v7 and is it safe to use yet?

    Time-ordered: 48 bits of Unix milliseconds followed by 74 random bits, standardised in RFC 9562 in May 2024. It is a published standard with support in current Postgres, in most language ecosystems and in a good number of libraries. It is a reasonable default for new work. The one property to be aware of is that it embeds a creation time, so a v7 identifier in a URL discloses roughly when the record was made.

    Is a UUID secure enough to use as a token?

    A v4 UUID from a cryptographic source has 122 bits of entropy, which is more than adequate for a password-reset link or a session identifier. Two caveats. First, the source has to actually be cryptographic — crypto.randomUUID is, most library implementations are, and anything built on Math.random() is not. Second, other versions are not suitable: v1 embeds a timestamp and historically a MAC address, v3 and v5 are deterministic hashes of their inputs, and v7 discloses its creation time. If it must be unguessable, use v4.

    Why is a UUID 36 characters when it is only 16 bytes?

    Because it is written in hexadecimal — two characters per byte, so 32 — plus four hyphens. Some systems store the 16 raw bytes instead, which is what MySQL BINARY(16) is for and roughly halves the storage. Others use a shorter text encoding: Base64 gives 22 characters, Base32 gives 26 and is case-insensitive. All of them are the same 128 bits wearing different clothes.

    Last reviewed . Found something out of date? Tell us.