Blog
Wild & Free Tools

UUID as a Primary Key — Should You Use It?

Last updated: January 2026 7 min read
Quick Answer

Table of Contents

  1. UUID vs Integer: The Real Tradeoff
  2. When to Use UUID as a Primary Key
  3. UUID Primary Keys by Database
  4. The Fragmentation Problem (and UUID v7)
  5. Generating Test UUIDs Quickly
  6. Frequently Asked Questions

UUID primary keys solve a real problem: how do you create unique IDs across multiple servers without a central counter? The answer — a 128-bit random identifier with a collision probability so low it is effectively impossible — is why every major database supports UUID natively. The question is whether that benefit outweighs the storage and index cost.

This guide covers the actual tradeoffs so you can choose the right primary key type for your use case, with SQL examples for PostgreSQL, MySQL, and SQL Server.

UUID vs Integer Primary Key: The Real Tradeoff

Integer primary keys are 4 bytes (INT) or 8 bytes (BIGINT). A UUID is 36 characters as a string — or 16 bytes as a binary value. That size difference compounds across every index, every foreign key, and every join.

FactorInteger (BIGINT)UUID v4
Storage per value8 bytes16 bytes (binary) / 36 bytes (text)
Index sizeSmaller, faster scans2–4x larger
Sequential insertsNaturally ordered — fast B-tree insertsRandom — causes page fragmentation
Distributed generationRequires central counter or coordinationAny node generates independently
GuessabilitySequential — easy to enumerate recordsRandom — not guessable via URL
Human readabilityEasy to type/shareVerbose, error-prone

The short version: integers win on performance in single-node systems. UUIDs win on scalability and security in distributed or public-facing systems.

When to Use UUID as a Primary Key

Use UUID when:

Use integer when:

Sell Custom Apparel — We Handle Printing & Free Shipping

How to Use UUID as a Primary Key in PostgreSQL, MySQL, and SQL Server

PostgreSQL (recommended approach)

-- Enable the extension (once per database)
CREATE EXTENSION IF NOT EXISTS "pgcrypto";

-- Or in PostgreSQL 13+, pgcrypto is built-in via gen_random_uuid()
CREATE TABLE orders (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  customer_id UUID NOT NULL,
  created_at TIMESTAMPTZ DEFAULT now()
);

PostgreSQL stores UUID natively as 16 bytes, so you don't pay the 36-byte text penalty.

MySQL 8+

CREATE TABLE orders (
  id BINARY(16) PRIMARY KEY DEFAULT (UUID_TO_BIN(UUID(), 1)),
  customer_id BINARY(16) NOT NULL,
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

-- Read back as string:
SELECT BIN_TO_UUID(id, 1) as id FROM orders;

The 1 flag in UUID_TO_BIN(UUID(), 1) reorders the time component, making sequential UUIDs for better index performance — this is essentially UUID v6 behavior.

SQL Server

CREATE TABLE orders (
  id UNIQUEIDENTIFIER PRIMARY KEY DEFAULT NEWSEQUENTIALID(),
  customer_id UNIQUEIDENTIFIER NOT NULL,
  created_at DATETIME2 DEFAULT GETUTCDATE()
);

Use NEWSEQUENTIALID() instead of NEWID() in SQL Server — it generates sequential GUIDs that avoid page fragmentation.

The Index Fragmentation Problem — and Why UUID v7 Solves It

The biggest performance complaint about UUID v4 primary keys is index fragmentation. Because v4 UUIDs are completely random, new rows insert at random positions in the B-tree index — not at the end. This causes "page splits" where the database has to shuffle existing data to make room, slowing inserts significantly on high-write tables.

There are three solutions:

If you are on a high-insert table (millions of rows/day), UUID v7 or an ordered variant is worth the upgrade. For most applications, standard UUID v4 performance is more than adequate.

Generating Test UUIDs Quickly

When you need to populate test data, seed a migration, or verify a query, you need UUIDs fast. The WildandFree UUID Generator generates v4 UUIDs instantly in your browser — one at a time or ten at a time, click to copy, no signup.

For bulk test data directly in SQL:

-- PostgreSQL: generate 1000 test UUIDs
SELECT gen_random_uuid() FROM generate_series(1, 1000);

-- MySQL 8+
SELECT UUID() FROM information_schema.columns LIMIT 1000;

-- SQL Server
SELECT NEWID() FROM sys.objects;

For application-level generation, see our guides on UUID in JavaScript/Node.js and UUID in Python.

Generate a UUID for Your Database Schema Now

Need a UUID to seed your migration, test query, or schema design? Generate one (or ten) instantly — no signup, no watermark, works in your browser.

Open Free UUID Generator

Frequently Asked Questions

Is UUID really unique enough to use as a primary key?

Yes. UUID v4 has 122 random bits, giving 2^122 possible values. If you generated 1 billion UUIDs per second for 100 years, the probability of a single collision would be roughly 50%. For any realistic database workload, collisions are not a practical concern.

Should I store UUIDs as strings or binary?

Binary (16 bytes) is always preferable for primary keys and indexed columns. String storage (36 chars as VARCHAR or CHAR) costs 2-4x more storage and makes indexes larger. PostgreSQL has a native UUID type that stores as 16 bytes. MySQL should use BINARY(16) with UUID_TO_BIN().

Can I combine a UUID primary key with an auto-increment ID?

Yes — this is a common pattern. Use an internal auto-increment integer ID for joins and performance, and a UUID as a public-facing "external ID" exposed via your API. This gives you the performance of integers internally and the security of UUIDs externally.

What is the difference between UUID and GUID?

Nothing meaningful for practical use. GUID (Globally Unique Identifier) is Microsoft's term for the same 128-bit identifier format. SQL Server uses UNIQUEIDENTIFIER/NEWID()/NEWSEQUENTIALID(). PostgreSQL and MySQL use UUID. The underlying format is identical. See our full GUID vs UUID guide.

Jennifer Hayes
Jennifer Hayes Business Documents & PDF Writer

Jennifer spent a decade as an executive assistant handling every type of business document imaginable.

More articles by Jennifer →
Launch Your Own Clothing Brand — No Inventory, No Risk