If you have spent any time building web applications, you have run into UUIDs. They show up as primary keys in databases, as identifiers in API responses, as session tokens, and as filenames for uploaded assets. Most developers grab a UUID library and move on without thinking much about what they are using. That works fine until it doesn't.
This guide covers how UUIDs are structured, what distinguishes the most common versions, and how to choose the right one for your situation. Whether you are starting a new project or auditing an existing codebase, understanding the version differences will save you from subtle bugs and performance surprises.
What Is a UUID and Why Does It Look Like That?
A UUID (Universally Unique Identifier) is a 128-bit value expressed as 32 hexadecimal characters grouped by hyphens. The standard form looks like this:
550e8400-e29b-41d4-a716-446655440000
The hyphens divide the value into five groups: 8-4-4-4-12 characters. They are not decorative. The fourth group always begins with a digit that encodes the UUID version. In the example above, the leading 4 indicates version 4. The fifth group begins with one of two specific hex digits that mark the variant, identifying this as an RFC 4122 UUID rather than an older platform-specific format or Microsoft GUID variant.
That 128-bit space holds 2^128 possible values, which comes out to roughly 340 undecillion unique identifiers. Collision probability between two independently generated UUIDs is so low that it is treated as zero for any practical purpose. No central authority is needed. Every node in a distributed system can generate a UUID locally and rely on it being globally unique.
Photo by Christina Morillo on Pexels
UUID Versions: What Actually Differs
The RFC 4122 standard defines five UUID versions. In day-to-day development you will encounter three of them.
Version 1: Timestamp Plus MAC Address
A v1 UUID encodes the current timestamp measured in 100-nanosecond intervals since October 15, 1582, combined with the MAC address of the generating machine. Two v1 UUIDs produced on the same machine at the same nanosecond get an additional clock sequence increment to avoid duplicate values.
The ordering property is the main reason teams reach for v1. Because the timestamp is embedded in the value, v1 UUIDs sort in generation order. In a table with a B-tree primary key index, sequential inserts reduce page splits compared to random values. Write-heavy workloads that care about insert performance can benefit from this.
The privacy cost is real, though. The MAC address embedded in every v1 UUID is readable by anyone who sees the value. If you expose v1 UUIDs in public URLs, API responses, or log files, you are revealing the hardware network identifier of the server that created them. In security-sensitive environments or when your infrastructure details should stay private, this matters.
Version 4: Cryptographically Random
V4 UUIDs are generated from cryptographically random data. Except for the four bits encoding the version and the two to three bits encoding the variant, every bit is random. There is no timestamp, no machine information, and no ordering.
This makes v4 the default for most use cases. The randomness guarantees that no information about your infrastructure leaks into your identifiers. It also means you cannot tell anything about when or where a v4 UUID was created just by looking at it.
The one tradeoff comes up in databases. Because v4 values are random, each new row's primary key is inserted at a random position in the B-tree index. At modest scale this has no measurable effect. At very high insert rates on large tables, the random writes can increase index fragmentation and reduce write throughput.
Modern environments make v4 generation straightforward. Browsers expose crypto.randomUUID() natively as part of the Web Crypto API. Node.js added the same method to its crypto module. For environments that need a consistent cross-platform interface, the uuid npm package provides v1, v4, and v5 generation with the same API.
Photo by Brett Sayles on Pexels
Version 5: Deterministic From Namespace and Name
V5 UUIDs work differently from v1 and v4. You provide two inputs: a namespace UUID and a name string. The generator computes a SHA-1 hash of the combined inputs and formats the result as a UUID. The critical property is determinism: the same namespace and name always produce the same UUID, on any machine, at any time.
This makes v5 useful when you need a stable, reproducible identifier for a known entity. Two common situations: content-addressable storage, where you want the identifier for a piece of content to be the same regardless of which system generates it, and deduplication, where you need to detect whether you have already processed a particular record without storing its original ID.
You need to agree on a namespace before generating v5 UUIDs. RFC 4122 defines four standard namespaces for DNS names, URLs, ISO object identifiers, and X.500 distinguished names. For application-specific uses, you can generate your own namespace UUID once and reuse it consistently.
Generating UUIDs Across Languages
The API surface is similar across most environments, though the details differ.
JavaScript and Node.js
// Native Web Crypto API (browsers and modern Node.js)
const id = crypto.randomUUID();
// Cross-environment uuid package (v4)
import { v4 as uuidv4, v5 as uuidv5 } from 'uuid';
const randomId = uuidv4();
// v5: deterministic from namespace + name
const MY_NAMESPACE = '6ba7b810-9dad-11d1-80b4-00c04fd430c8';
const deterministicId = uuidv5('my-entity-name', MY_NAMESPACE);
Python
import uuid
# v4 random
random_id = str(uuid.uuid4())
# v5 deterministic
ns = uuid.NAMESPACE_DNS
deterministic_id = str(uuid.uuid5(ns, 'example.com'))
PostgreSQL
-- v4 via pgcrypto extension (ships with most managed databases)
SELECT gen_random_uuid();
-- v4 via uuid-ossp extension
SELECT uuid_generate_v4();
PostgreSQL supports UUID generation through two extensions. The pgcrypto extension is available on virtually every managed PostgreSQL service and is the simpler choice for most teams. The MDN documentation covers the browser-side crypto.randomUUID() method including browser support status.
Photo by cocoparisienne on Pixabay
UUID in Database Design
The database implications of UUID primary keys come up in almost every architecture discussion, and the answer depends on your scale and access patterns.
When you use a UUID as a primary key in a standard B-tree index, each new row lands at a random position in the index tree. For write-heavy tables, this means more frequent page splits and higher index fragmentation over time compared to sequential integer primary keys. The difference is negligible at tens of thousands of rows. At tens of millions of rows with sustained high-volume inserts, it shows up as measurable latency increases.
There are a few approaches teams take. For tables where insert order matters, some databases support UUID v7, a newer format not yet formally standardized in RFC 4122 that uses a millisecond-precision timestamp prefix. ULIDs (Universally Unique Lexicographically Sortable Identifiers) solve the same problem with a slightly different encoding. Both give you globally unique identifiers that also sort by creation time.
For most applications, the simpler choice is to keep integer IDs as internal primary keys and expose UUID-formatted values at the API layer. This gives you sequential index inserts internally while presenting opaque, unguessable identifiers to clients.
"We have seen teams spend real debugging time on subtle data integrity issues that trace back to mixing UUID versions in the same foreign key column. Pick one version and enforce it at the schema level from the start." - Dennis Traina, founder of 137Foundry
The tools directory on EvvyTools includes a UUID generator that handles validation as well as generation. If you are auditing a codebase, pasting a UUID into the validator immediately tells you which version produced it and whether the variant field is correct.
Using the UUID Generator
The free UUID generator by EvvyTools covers the cases that come up most often in development workflows without needing to install anything or open a REPL.
For random IDs, the generator produces v4 UUIDs using the same cryptographic source as crypto.randomUUID(). For deterministic IDs, you enter a namespace and a name string and get a v5 UUID. Bulk generation is available for up to 100 values at once, which is useful when seeding test databases or generating a batch of identifiers for an import pipeline.
The validator accepts any UUID-formatted string and reports the version and variant. This is particularly useful when working with legacy code or third-party integrations where the UUID source is not documented.
Quick Reference: Which Version to Use
When in doubt, v4 is the right default. The only reasons to deviate are:
- Use v5 when the same entity must produce the same ID across independent systems, such as in event sourcing, content deduplication, or cross-service entity resolution.
- Use v1 only when insert ordering matters and the identifiers will never appear in public URLs, API responses, or logs.
- Use a sortable format (ULID, v7) when you have a write-heavy table that will scale to hundreds of millions of rows and insert latency is a documented concern.
If you are choosing a format for a new project, v4 with integer internal keys is the most flexible starting point. It keeps your indexes efficient, keeps your APIs clean, and avoids leaking infrastructure details.
Photo by Atlantic Ambience on Pexels
Summary
UUIDs are 128-bit identifiers designed for distributed generation without any central coordination. The version digit inside the UUID tells you how it was generated. V4 is cryptographically random and the right default for most applications. V5 is deterministic and the right choice when you need reproducible IDs from known inputs. V1 is sortable by timestamp but embeds machine hardware information that may not be appropriate to expose.
For generating or validating UUIDs during development, browse the EvvyTools blog for more developer guides alongside the free toolset.