Skip to main content
HomeBlogWhat Is a UUID?
UUIDGUIDPythonJavaScriptDatabasesDeveloper Tools

What Is a UUID? Complete Guide to Generating & Using Unique Identifiers

A comprehensive guide to UUID versions, structure, database usage, security considerations, and how to generate UUIDs in Python, JavaScript, Java, and more — with code examples.

15 min read
Updated 2025
Beginner & Advanced

TL;DR — Quick Summary

  • A UUID is a 128-bit globally unique identifier standardized by RFC 4122
  • UUID v4 (random) is recommended for most use cases — 122 bits of cryptographic randomness
  • Python: import uuid; uuid.uuid4()
  • JavaScript: crypto.randomUUID()
  • No-code: use the QuickTextTools UUID Generator to generate up to 1000 at once

What Is a UUID?

A UUID (Universally Unique Identifier) is a 128-bit label used for information in computer systems. Standardized by the Open Software Foundation (OSF) as part of the Distributed Computing Environment (DCE) and formalized in RFC 4122, UUIDs are designed to be unique across space and time without requiring a central registration authority.

Unlike a sequential ID generated by a database (1, 2, 3, ...), a UUID can be independently generated by any system — a web browser, a mobile app, a microservice running in another country — and the probability that two independently generated UUIDs will be identical is effectively zero.

A UUID looks like this:
550e8400-e29b-41d4-a716-446655440000
550e8400
time_low
e29b
time_mid
41d4
time_hi+ver
a716
clk_seq
446655440000
node

The format is standardized as five groups of hexadecimal digits separated by hyphens in the pattern 8-4-4-4-12, totaling 32 hex digits (128 bits) plus 4 hyphens — 36 characters in total.

UUID Structure Explained

Every UUID field has a defined purpose in the RFC 4122 specification. The meaning of each field varies by UUID version, but the structural positions are fixed.

FieldLengthDescription
time_low4 bytes (8 hex)Low 32 bits of time (v1) or random bits (v4)
time_mid2 bytes (4 hex)Middle 16 bits of time (v1) or random bits (v4)
time_hi_and_version2 bytes (4 hex)High 12 bits of time + 4-bit version number
clock_seq_and_reserved2 bytes (4 hex)Clock sequence + 2-bit variant identifier
node6 bytes (12 hex)MAC address (v1) or random bits (v4)

The Version and Variant Bits

Two fields in every UUID are reserved for metadata — not random data:

  • Version digit: The first digit of the third group encodes the UUID version (1–5). In UUID v4: xxxxxxxx-xxxx-4xxx-... — the 4 is fixed.
  • Variant bits: The first digit of the fourth group is restricted to 8, 9, a, or b in RFC 4122 UUIDs — encoding the variant (DCE 1.1). This is why v4 UUIDs look like ...-4xxx-[89ab]xxx-....

UUID Versions: v1, v3, v4, v5 (and v7)

RFC 4122 defines five UUID versions. Each uses a different algorithm to generate the 128-bit value. Understanding the differences helps you choose the right version for your use case.

Version 1 — Time-Based

6ba7b810-9dad-11d1-80b4-00c04fd430c8
ADVANTAGES
  • Sortable by creation time
  • Monotonically increasing on same machine
DISADVANTAGES
  • Reveals MAC address (privacy risk)
  • Requires a clock and sequence counter
  • Not safe for public-facing identifiers
BEST FOR

Internal audit logs, event sourcing systems where time ordering matters and privacy is not a concern.

Version 3 — Name-Based (MD5)

6fa459ea-ee8a-3ca4-894e-db77e160355e
ADVANTAGES
  • Deterministic — same inputs always produce same UUID
  • No randomness required
DISADVANTAGES
  • MD5 is cryptographically broken
  • Not unique if names collide
  • Deprecated in favor of v5
BEST FOR

Legacy systems. Avoid for new development — use v5 instead.

Version 4 — Random (Recommended)

550e8400-e29b-41d4-a716-446655440000
ADVANTAGES
  • 122 bits of cryptographic randomness
  • No system information exposed
  • Simple to generate on any platform
  • Supported everywhere
DISADVANTAGES
  • Not time-sortable
  • Random insertion hurts B-tree index performance at very high volume
BEST FOR

Database primary keys, API resource IDs, session tokens, file names — the universal default choice.

Version 5 — Name-Based (SHA-1)

886313e1-3b8a-5372-9b90-0c9aee199e5d
ADVANTAGES
  • Deterministic and reproducible
  • Better than v3 (SHA-1 vs MD5)
  • Same name+namespace always gives same UUID
DISADVANTAGES
  • SHA-1 is also deprecated for cryptographic use
  • Same collision risk as v3 for name conflicts
BEST FOR

Deterministic ID generation from known inputs — URL slugs, content hashing, namespace-scoped identifiers.

Version 7 — Time-Ordered Random (Modern)

018e57cb-2b8e-7000-8000-000000000000
ADVANTAGES
  • Lexicographically sortable by creation time
  • Sufficient randomness for uniqueness
  • Better database index performance than v4
  • Defined in RFC 9562 (2024)
DISADVANTAGES
  • Not yet supported natively in all languages
  • Requires library support in most environments
BEST FOR

Modern database primary keys where time ordering is desired. Increasingly recommended over v4 for new systems.

UUID vs GUID — What's the Difference?

The short answer: there is no technical difference. UUID and GUID refer to the same 128-bit identifier format. The naming divergence is purely historical and organizational.

UUID

Universally Unique Identifier — the term used in RFC 4122, the IETF standard. Used in Unix/Linux systems, open-source ecosystems, web APIs, and cross-platform contexts. Python's <code className="bg-violet-100 px-1 rounded">uuid</code> module, PostgreSQL's <code className="bg-violet-100 px-1 rounded">UUID</code> type, and JavaScript's <code className="bg-violet-100 px-1 rounded">crypto.randomUUID()</code> all use this terminology.

GUID

Globally Unique Identifier — Microsoft's equivalent term. Used in Windows APIs, COM interfaces, .NET's <code className="bg-blue-100 px-1 rounded">System.Guid</code>, SQL Server's <code className="bg-blue-100 px-1 rounded">UNIQUEIDENTIFIER</code> type, and Visual Studio tooling. Functionally identical to UUID — same format, same uniqueness guarantees.

One subtle difference: Microsoft's GUID generation historically used a mixed-endian byte order for the first three fields (little-endian) compared to the big-endian order in RFC 4122. This affects binary representation in SQL Server's <code className="bg-gray-100 px-1 rounded">UNIQUEIDENTIFIER</code> type but not the string representation. When comparing GUIDs and UUIDs as strings, they look and behave identically.

Generate UUIDs in Python

Python's built-in uuid module provides complete UUID generation with no external dependencies required.

Basic UUID Generation

import uuid

        # UUID v4 — recommended, random
        v4 = uuid.uuid4()

        print(v4)
        # 550e8400-e29b-41d4-a716-446655440000

        print(str(v4))
        # same, as string

        print(v4.hex)
        # 550e8400e29b41d4a716446655440000 (no dashes)

        print(v4.int)
        # 113059749145936325402354257176981405696 (integer)

        print(v4.bytes)
        # raw bytes (16 bytes)

        # UUID v1 — time-based
        v1 = uuid.uuid1()

        print(v1)
        # 6ba7b810-9dad-11d1-80b4-00c04fd430c8

        # UUID v5 — name-based (SHA-1)
        v5 = uuid.uuid5(
            uuid.NAMESPACE_URL,
            'https://quicktexttools.in'
        )

        print(v5)
        # deterministic — same output every time for same input

        # Nil UUID
        nil = uuid.UUID(int=0)

        print(nil)
        # 00000000-0000-0000-0000-000000000000

Bulk UUID Generation

import uuid

        def generate_uuids(
            count: int,
            uppercase: bool = False,
            no_dashes: bool = False
        ) -> list[str]:

            results = []

            for _ in range(count):
                u = str(uuid.uuid4())

                if no_dashes:
                    u = u.replace('-', '')

                if uppercase:
                    u = u.upper()

                results.append(u)

            return results

        # Generate 1000 UUIDs and save to file
        uuids = generate_uuids(1000)

        with open('uuids.txt', 'w') as f:
            f.write('\n'.join(uuids))

        print(f"Saved {len(uuids)} UUIDs to uuids.txt")

UUID Validation in Python

import uuid

        def is_valid_uuid(value: str) -> bool:
            try:
                uuid.UUID(str(value))
                return True

            except ValueError:
                return False

        print(
            is_valid_uuid(
                "550e8400-e29b-41d4-a716-446655440000"
            )
        )
        # True

        print(
            is_valid_uuid("not-a-uuid")
        )
        # False

        print(
            is_valid_uuid(
                "550e8400e29b41d4a716446655440000"
            )
        )
        # True (no dashes OK)

        # Validate and get version
        def get_uuid_version(value: str) -> int | None:
            try:
                return uuid.UUID(str(value)).version

            except ValueError:
                return None

Generate UUIDs in JavaScript

Modern JavaScript environments expose the Web Crypto API's <code className="bg-gray-100 px-1 rounded">crypto.randomUUID()</code> method — the fastest and most reliable way to generate UUID v4 with no dependencies.

Browser & Node.js 19+ (Native)

// Native — works in modern browsers and Node.js 19+
        const uuid = crypto.randomUUID();

        console.log(uuid);
        // '550e8400-e29b-41d4-a716-446655440000'

        // Bulk generation
        function generateUuids(
          count,
          { uppercase = false, noDashes = false } = {}
        ) {
          return Array.from(
            { length: count },
            () => {
              let u = crypto.randomUUID();

              if (noDashes) {
                u = u.replace(/-/g, '');
              }

              if (uppercase) {
                u = u.toUpperCase();
              }

              return u;
            }
          );
        }

        const uuids = generateUuids(
          100,
          { uppercase: true }
        );

        console.log(uuids.length);
        // 100

With the uuid npm Package (Universal)

// npm install uuid

        import {
          v4 as uuidv4,
          v1 as uuidv1,
          v5 as uuidv5,
          NIL,
          validate,
          version,
        } from 'uuid';

        // v4 — random
        console.log(uuidv4());
        // 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'

        // v1 — time-based
        console.log(uuidv1());
        // time-ordered UUID

        // v5 — name-based
        const NAMESPACE =
          '6ba7b810-9dad-11d1-80b4-00c04fd430c8';

        console.log(
          uuidv5('hello', NAMESPACE)
        );
        // deterministic

        // nil UUID
        console.log(NIL);
        // '00000000-0000-0000-0000-000000000000'

        // Validation
        console.log(
          validate(
            '550e8400-e29b-41d4-a716-446655440000'
          )
        );
        // true

        console.log(
          version(
            '550e8400-e29b-41d4-a716-446655440000'
          )
        );
        // 4

Polyfill for Older Browsers

function generateUUIDv4() {   if (typeof crypto !== 'undefined' && crypto.randomUUID) {     return crypto.randomUUID();   }   // Fallback using Math.random (less secure — use only if crypto unavailable)   return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {     const r = Math.random() * 16 | 0;     const v = c === 'x' ? r : (r & 0x3 | 0x8);     return v.toString(16);   }); }

Generate UUIDs in Java & Other Languages

Java
import java.util.UUID;

        // UUID v4 — random
        UUID uuid = UUID.randomUUID();

        System.out.println(uuid.toString());
        // "550e8400-e29b-41d4-a716-446655440000"

        // Without dashes
        String compact =
            uuid.toString().replace("-", "");

        System.out.println(compact);

        // UUID v3 (name-based)
        UUID v3 =
            UUID.nameUUIDFromBytes(
                "hello".getBytes()
            );

        // Validate a UUID string
        UUID parsed =
            UUID.fromString(
                "550e8400-e29b-41d4-a716-446655440000"
            );
C# / .NET
using System;

            // UUID (GUID) v4
            Guid guid = Guid.NewGuid();

            Console.WriteLine(guid.ToString());
            // lowercase with dashes

            Console.WriteLine(guid.ToString("N"));
            // compact, no dashes

            Console.WriteLine(guid.ToString("B"));
            // {with-braces}

            Console.WriteLine(guid.ToString("X"));
            // {0x...,0x...} hex format

            // Nil GUID
            Guid nil = Guid.Empty;

            Console.WriteLine(nil);
            // 00000000-0000-0000-0000-000000000000

            // Parse and validate
            bool isValid = Guid.TryParse(
                "550e8400-e29b-41d4-a716-446655440000",
                out Guid result
            );
Go
// go get github.com/google/uuid

            package main

            import (
                "fmt"
                "github.com/google/uuid"
            )

            func main() {

                // UUID v4
                id := uuid.New()

                fmt.Println(id.String())

                // UUID v1
                id1, _ := uuid.NewUUID()

                fmt.Println(id1.String())

                // Nil UUID
                fmt.Println(uuid.Nil.String())

                // Validate
                parsed, err := uuid.Parse(
                    "550e8400-e29b-41d4-a716-446655440000"
                )

                fmt.Println(parsed, err)
            }

UUIDs in Databases

Database support for UUIDs varies significantly. Choosing the right storage strategy has meaningful performance implications at scale.

PostgreSQL

STORAGE TYPE

Native UUID type (16 bytes)

GENERATION

gen_random_uuid() (pgcrypto) or uuid_generate_v4() (uuid-ossp)

PostgreSQL has the best native UUID support. Use UUID as the column type directly. The gen_random_uuid() function is available without extensions in PostgreSQL 13+.

CREATE TABLE users (id UUID PRIMARY KEY DEFAULT gen_random_uuid());

MySQL / MariaDB

STORAGE TYPE

BINARY(16) recommended; CHAR(36) as fallback

GENERATION

UUID() built-in function (v1); application-side for v4

MySQL 8.0+ includes UUID_TO_BIN() and BIN_TO_UUID() helpers. For MySQL 8.0.13+, UUID_TO_BIN(uuid, true) swaps bytes for better index performance.

CREATE TABLE users (id BINARY(16) PRIMARY KEY DEFAULT (UUID_TO_BIN(UUID(), 1)));

SQL Server

STORAGE TYPE

UNIQUEIDENTIFIER (native 16-byte type)

GENERATION

NEWID() (random) or NEWSEQUENTIALID() (sequential, index-friendly)

NEWSEQUENTIALID() generates sequential GUIDs optimized for clustered index performance. Use NEWID() for security-sensitive public identifiers.

CREATE TABLE users (id UNIQUEIDENTIFIER PRIMARY KEY DEFAULT NEWSEQUENTIALID());

SQLite

STORAGE TYPE

TEXT (no native UUID type)

GENERATION

Application-side generation required

SQLite has no UUID type or generation function. Store as TEXT(36) with dashes or BLOB(16) for compactness. Generate UUID v4 in your application layer.

CREATE TABLE users (id TEXT PRIMARY KEY); -- insert UUIDs from application

UUID vs Auto-Increment Primary Keys

This is one of the most frequently debated decisions in backend architecture. There is no universal right answer — the correct choice depends on your system's requirements.

CriterionUUID v4Auto-Increment
Global uniqueness✅ Guaranteed across systems❌ Only unique within one database
Index performance⚠️ Random insertion causes page splits✅ Sequential — optimal B-tree performance
Storage size⚠️ 16 bytes (BINARY) or 36 bytes (TEXT)✅ 4–8 bytes (INT/BIGINT)
Predictability/security✅ Non-guessable, non-sequential❌ Sequential — enables enumeration attacks
Client-side generation✅ Generate anywhere without DB❌ Requires database round-trip
Distributed systems✅ No coordination needed❌ Requires centralized counter or sharding
Human readability❌ 36-character opaque string✅ Short, readable integers
Merge/replication✅ No ID conflicts across nodes❌ ID conflicts require remapping

The Hybrid Approach — Best of Both Worlds

Many modern systems use both: an auto-increment integer as the internal primary key (for join performance and index efficiency) alongside a UUID column as the public identifier (for API resources and external references). The integer key is never exposed; all external APIs use the UUID. This gives optimal database performance while maintaining the security and distribution benefits of UUIDs.

UUID Security Considerations

UUID v4 is safe for public-facing identifiers

With 122 bits of cryptographic randomness from the OS CSPRNG, UUID v4 is unpredictable and resistant to brute-force guessing. An attacker cannot enumerate resources by incrementing an ID or predict the next UUID from previous ones.

UUID v1 leaks system information

UUID v1 embeds the MAC address of the generating machine in the node field. This can be used to identify the specific hardware that generated the UUID — a potential privacy and security issue for public-facing identifiers. Always use v4 for public IDs.

UUIDs are not secrets — they are identifiers

A UUID used as a resource ID is not a secret. If a user can access a resource at /api/documents/550e8400-..., they know the UUID. A UUID's security comes from its unpredictability, not from being hidden. For true secrets (passwords, API keys), use a cryptographically random token of at least 256 bits, not a UUID.

Always enforce authorization, not just obscurity

Do not rely on UUID unpredictability as your only authorization mechanism. Always check that the requesting user has permission to access the resource with that UUID. UUID unpredictability is a defense-in-depth measure, not a substitute for proper access control.

Best Practices for Working with UUIDs

Use UUID v4 as your default choice

Unless you have a specific reason to use v1 (time-sorting) or v5 (deterministic), UUID v4 is the correct default for all new applications.

Store as BINARY(16), not VARCHAR(36)

Binary storage is 2.25× more compact than string storage and index lookups are significantly faster. Only convert to string representation at the application boundary.

Always enforce a UNIQUE database constraint

Even though UUID collisions are effectively impossible, a UNIQUE constraint is correct schema design. It documents your intent and provides a safety net.

Normalize case before storage

Choose lowercase (RFC 4122 standard) and enforce it consistently. Mixed-case UUIDs that differ only by case create subtle bugs in case-sensitive comparisons.

Consider UUID v7 for new high-throughput systems

UUID v7's time-ordered prefix maintains B-tree index locality while providing sufficient randomness. For new greenfield projects with high insert rates, v7 is worth evaluating.

Use crypto.randomUUID() in the browser, not Math.random()

Math.random() is not cryptographically secure. Always use the Web Crypto API's crypto.randomUUID() for any UUID used in a security-sensitive context.

Common Mistakes to Avoid

Using Math.random() to generate UUIDs in JavaScript

Math.random() is not cryptographically secure. Its output is predictable with sufficient observation. Always use crypto.randomUUID() or the uuid npm package which uses the CSPRNG under the hood.

Treating UUIDs as case-sensitive strings without normalization

An API that stores UUIDs as generated (mixed or uppercase) will fail to find records when the client sends the UUID in a different case. Always normalize to lowercase before storage and lookup.

Using UUID v1 for public-facing resource identifiers

UUID v1 embeds your server's MAC address and can be used to reconstruct the approximate time a resource was created. Use UUID v4 for any identifier exposed outside your system.

Skipping the UNIQUE constraint because 'UUIDs can't collide'

Relying on collision impossibility as your uniqueness guarantee is an engineering antipattern. The UNIQUE constraint is correct schema design regardless of collision probability.

Storing UUIDs as VARCHAR(36) in performance-critical tables

String-based UUID storage bloats indexes and slows lookups compared to BINARY(16). For tables with millions of rows, this becomes a significant performance bottleneck.

Generate UUIDs Instantly — No Code Required

Bulk generate up to 1000 UUID v4, v1, or nil identifiers with formatting options. Copy or download instantly.

Open UUID Generator Tool

Frequently Asked Questions

Conclusion

UUIDs are a foundational tool in modern software engineering — essential for distributed systems, secure API design, and scalable database architecture. Understanding the differences between versions, the storage trade-offs across database engines, and the security implications of each version allows you to make informed decisions rather than cargo-culting a solution from a Stack Overflow snippet.

For the vast majority of use cases, UUID v4 generated using your platform's cryptographically secure random number generator is the right choice. For high-throughput database workloads where index performance is critical, evaluate UUID v7 or a hybrid approach. For deterministic identifier generation from known inputs, v5 is the correct tool.

Store UUIDs as BINARY(16) in performance-critical tables, always enforce a UNIQUE constraint, normalize to lowercase, and use the UUID as a public identifier alongside an auto-increment surrogate key when maximum index performance is required.