UUID vs GUID: Same Thing, Different Ecosystem

21 March, 2026 Backend

GUID and UUID are the same 128-bit identifier defined in RFC 4122. The distinction is ecosystem: Microsoft coined GUID (Globally Unique Identifier) for the COM/Windows world; the rest of the industry uses UUID (Universally Unique Identifier). Copy a GUID into a UUID field and it works - because they are structurally identical.

The nuances that do exist - case conventions, brace notation, SQL Server's sequential variant - are worth understanding because they affect interoperability, database performance, and a few non-obvious bugs.

The Core Format

Both UUID and GUID share the same 128-bit structure: five hyphen-separated groups of hex digits in an 8-4-4-4-12 layout:

550e8400-e29b-41d4-a716-446655440000
xxxxxxxx-xxxx-4xxx-[89ab]xxx-xxxxxxxxxxxx
              ↑    ↑
         version=4  variant bits (RFC 4122)

The version nibble is 4, variant bits are 10xx (hex 8-b), and the remaining 122 bits are random. This structure is identical whether you call it a UUID or a GUID. Try the UUID v4 generator to see the format in action.


The Differences That Actually Exist

Case Convention

UUIDs are lowercase everywhere outside the Microsoft ecosystem:

# UUID - standard, lowercase
550e8400-e29b-41d4-a716-446655440000

# GUID - Windows/COM/SQL Server output, uppercase
550E8400-E29B-41D4-A716-446655440000

This is cosmetic at the data level - hex is case-insensitive - but it causes real problems with string comparisons in case-sensitive databases (MySQL with utf8_bin collation, for example) and in application code that does naive string equality checks instead of normalising first.

Brace Notation

Windows registry, COM interfaces, and some .NET serialization formats wrap the GUID in curly braces:

{550E8400-E29B-41D4-A716-446655440000}

The braces are not part of the identifier - they are a display convention. Guid.ToString("B") in C# produces the braced form; Guid.ToString("D") produces bare digits. When exchanging IDs between a .NET service and anything else, strip the braces and normalise case before comparison.

Variant Bits

Historical COM GUIDs used a different variant encoding (bits 62-63 = 110, hex c/d) from the RFC 4122 variant (10, hex 8-b). Modern Guid.NewGuid() generates RFC 4122-compliant v4 UUIDs, so this difference only surfaces with legacy COM identifiers embedded in old registry entries or Windows system files.


SQL Server Specifics

The uniqueidentifier Type

SQL Server stores GUIDs as uniqueidentifier (16 bytes, uppercase display). NEWID() generates a random v4-equivalent GUID - the analog of PostgreSQL's gen_random_uuid():

SELECT NEWID();
-- 6F9619FF-8B86-D011-B42D-00CF4FC964FF

Index Fragmentation Problem

Random GUIDs as clustered primary keys cause B-tree fragmentation. Every NEWID() value lands at a random position in the tree, forcing random page reads and triggering page splits (a page fills up, gets split in two, both pages end up ~50% full). Over millions of inserts the index is riddled with half-empty pages; range scans become random I/O.

The effect is measurable at ~5-10 million rows and severe beyond 50 million on write-heavy tables.

NEWSEQUENTIALID(): SQL Server's Solution

NEWSEQUENTIALID() generates monotonically increasing GUIDs within a server restart boundary:

CREATE TABLE orders (
    id UNIQUEIDENTIFIER NOT NULL DEFAULT NEWSEQUENTIALID(),
    created_at DATETIME2 NOT NULL DEFAULT SYSUTCDATETIME(),
    CONSTRAINT PK_orders PRIMARY KEY CLUSTERED (id)
);

Sequential GUIDs insert at the rightmost leaf of the B-tree, eliminating page splits. The trade-off: values reset to a new (but still increasing) sequence on server restart, and the sequential pattern reveals insertion order in public-facing IDs.

NEWSEQUENTIALID() cannot be called outside a DEFAULT constraint - it cannot be invoked in application code. To retrieve the generated GUID after insert, use the OUTPUT clause:

INSERT INTO orders (payload) OUTPUT INSERTED.id VALUES ('...');

UUID v7: The Cross-Platform Solution

SQL Server's NEWSEQUENTIALID() solves fragmentation but requires server-side generation. If you need the ID in application code before the insert - to include it in a message queue payload, use it in multiple tables, or avoid a round trip - UUID v7 is the right choice:

018e2b3d-a1c2-7000-b0e5-4a9f1c8d7e2a
└──────────────┘
  48-bit Unix ms timestamp

UUID v7 is monotonically increasing (millisecond precision), RFC 9562 standardised, and generated in application code. It solves the same fragmentation problem as NEWSEQUENTIALID() while working on any database and any platform. Compare the output with the UUID v7 generator to see the embedded timestamp.


.NET: Working with GUIDs

Guid id = Guid.NewGuid();              // RFC 4122 v4

id.ToString("D");  // 550e8400-e29b-41d4-a716-446655440000 (no braces)
id.ToString("B");  // {550E8400-E29B-41D4-A716-446655440000} (braces)
id.ToString("N");  // 550e8400e29b41d4a716446655440000 (no hyphens)

Guid.Parse("{550E8400-E29B-41D4-A716-446655440000}"); // accepts any case + braces
Guid.TryParse(input, out Guid result);

Guid.Empty; // 00000000-0000-0000-0000-000000000000

// EF Core + SQL Server: DB generates the sequential GUID
public class Order
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; }
}

For application-side sequential GUIDs, use the UuidNext NuGet package - it generates v7-compatible time-ordered values without a database round trip.


PHP: ramsey/uuid and Symfony

<?php
// ramsey/uuid
use Ramsey\Uuid\Uuid;
$id = Uuid::uuid4()->toString(); // random
$id = Uuid::uuid7()->toString(); // time-ordered

// symfony/uid (ships with Symfony)
use Symfony\Component\Uid\Uuid;
$v4 = Uuid::v4()->toRfc4122();
$v7 = Uuid::v7()->toRfc4122();
$binary = Uuid::v7()->toBinary(); // 16-byte string for BINARY(16) column

Uuid::v7() is the right default for new Symfony projects on MySQL or any database with a clustered primary key index.


Common Mistakes

Storing as VARCHAR(36) Instead of a Native Type

-- Wrong: wastes space, slower comparisons, prevents native functions
id VARCHAR(36) NOT NULL

-- Correct for SQL Server
id UNIQUEIDENTIFIER NOT NULL DEFAULT NEWSEQUENTIALID()

-- Correct for PostgreSQL
id UUID NOT NULL DEFAULT gen_random_uuid()

-- Correct for MySQL (no native UUID type before 8.0)
id BINARY(16) NOT NULL

At 100 million rows, VARCHAR(36) vs BINARY(16) for the primary key index alone is a ~2 GB difference. String comparison for GUIDs requires a full 36-byte compare; binary comparison is fixed-width 16 bytes and significantly faster at scale.

Generating IDs in the Database When You Need Them Earlier

If your application needs the primary key before the insert - for a message queue payload, a distributed trace, or a second table in the same transaction - database-side generation forces an insert-then-read. Application-side UUID v7 generation eliminates the round trip.


Decision Table

Use case Recommendation
General purpose, no specific constraints UUID v4
Database primary key, write-heavy table UUID v7
SQL Server, server-side generation NEWSEQUENTIALID()
.NET application-side generation Guid.NewGuid() (v4) or UuidNext (v7)
MongoDB document IDs ObjectID (12-byte, built-in)
Deterministic ID from known input UUID v5
Legacy COM / Windows registry GUID (whatever format the system expects)

The Short Version

GUID and UUID are the same identifier. The practical differences are case convention, brace notation in Windows contexts, and SQL Server's NEWSEQUENTIALID() extension. For new systems, use UUID v7 for primary keys — it solves fragmentation, works with application-side generation, and is IETF standardised.

More Articles

CSV vs JSON for Data Exchange: When Each Format Wins

A practical comparison of CSV and JSON for APIs, data pipelines, and file exports. Covers structure, parsing, streaming, schema enforcement, size, tooling, and clear guidelines for choosing the right format.

15 April, 2026

SEO for AI Search: How to Optimise for ChatGPT, Perplexity, and Google AI Overviews

How AI-powered search engines discover, evaluate, and cite web content. Practical strategies for optimising your pages for ChatGPT Browse, Perplexity, Google AI Overviews, and other AI answer engines.

14 April, 2026

Image to Base64 Data URIs: When to Inline and When Not To

A practical guide to embedding images as Base64 data URIs. Covers the data URI format, size overhead, performance trade-offs, browser caching, Content Security Policy, and clear rules for when inlining helps vs hurts.

10 April, 2026