UUID vs GUID: Differences, Compatibility, and Gotchas
Learn how UUIDs and GUIDs relate, understand .NET byte-order differences, and choose a safe interchange format for your application stack.
When designing database schemas, message queues, and cross-platform APIs, software engineers constantly encounter two terms: UUID (Universally Unique Identifier) and GUID (Globally Unique Identifier). Are they different technologies, interchangeable synonyms, or subtly incompatible implementations?
The short answer is: in textual representation, UUID and GUID refer to the exact same 128-bit identifier format. A standard random GUID generated in Microsoft .NET is fully compatible with an RFC 4122 UUID v4 used in Linux, Java, Python, or PostgreSQL. However, beneath the surface lies a critical technical trap: Microsoft's binary storage uses a mixed-endian memory layout, causing raw byte arrays to deserialize into completely different string values when transferred between .NET and non-Microsoft systems.
You can generate and format identifiers using ToolPorta's GUID Generator or UUID Generator. This guide covers their origins, the mixed-endian byte-array gotcha, text conventions, and practical interoperability rules.
Format and text structure#
Both UUID and GUID consist of 128 bits (16 bytes). In string form, they are displayed as 32 hexadecimal digits divided into five hyphen-separated groups according to the canonical 8-4-4-4-12 pattern:
- Group 1 (8 hex chars / 32 bits): Low time or pseudo-random data.
- Group 2 (4 hex chars / 16 bits): Mid time or pseudo-random data.
- Group 3 (4 hex chars / 16 bits): High time multiplexed with the 4-bit version number
M(e.g.,4for random,7for time-ordered). - Group 4 (4 hex chars / 16 bits): Variant bit field
N(typically8,9,a, orbfor standard RFC/DCE variant) plus clock sequence or random entropy. - Group 5 (12 hex chars / 48 bits): Node MAC address (in v1) or cryptographically secure pseudo-random bytes (in v4).
Typical representation conventions#
While the underlying 128-bit values are identical, the ecosystems surrounding them developed distinct stylistic conventions:
| Feature | Standard UUID (RFC 4122 / RFC 9562) | Microsoft GUID (Windows / .NET / COM) |
|---|---|---|
| Letter Case | Uppercase, lowercase, or mixed hexadecimal is valid | Often uppercase in Microsoft examples |
| Enclosing Braces | No braces (e04f...) | Frequently enclosed in braces ({E04F...}) |
| Nil / Empty State | Nil UUID (00000000-0000-0000-0000-000000000000) | Guid.Empty (00000000-0000-0000-0000-000000000000) |
| Primary Context | Web APIs, Linux, Java, Python, PostgreSQL | C#, .NET, Windows Registry, COM, SQL Server |
When exchanging data over JSON APIs, choosing one canonical form—commonly lowercase with hyphens and no braces—simplifies comparison and logging. Case alone does not change the 128-bit value.
The critical gotcha: The mixed-endian binary byte swap#
The most dangerous pitfall when bridging .NET and non-Microsoft ecosystems occurs when transferring raw binary representations (16 bytes) rather than string representations.
The Win32 C struct legacy#
In the original Windows C/C++ header files, a GUID was defined not as a flat 16-byte array, but as a composite structure:
Because x86 and x64 processors are little-endian, multibyte integer types are stored in memory with their least significant byte first:
Data1(4 bytes) is stored in little-endian byte order.Data2(2 bytes) is stored in little-endian byte order.Data3(2 bytes) is stored in little-endian byte order.Data4is an array of 8 individual bytes, so it is stored sequentially (big-endian).
Conversely, RFC 4122 and RFC 9562 specify that UUIDs must always be stored in big-endian (network byte order), matching their left-to-right hexadecimal string representation.
What happens when you call Guid.ToByteArray()#
Consider the following valid identifier:
If you serialize this identifier to a 16-byte array in standard RFC 4122 (big-endian) vs default .NET Guid.ToByteArray() on an x86/x64 machine:
Notice the discrepancy:
- The first 4 bytes (
Data1) are reversed:01 23 45 67becomes67 45 23 01. - The next 2 bytes (
Data2) are reversed:89 abbecomesab 89. - The next 2 bytes (
Data3) are reversed:cd efbecomesef cd. - The remaining 8 bytes (
Data4) remain identical.
If a .NET service saves raw bytes generated by Guid.ToByteArray() into a Kafka message or binary database column, and a Java or Go consumer reads those bytes as a standard RFC 4122 UUID, the consumer produces an entirely different string:
The record cannot be found, foreign key relationships break, and distributed lookups fail silently.
How to fix the endianness mismatch in modern .NET#
Prior to modern .NET, developers had to manually swap bytes before sending binary UUIDs across the wire. Starting in .NET Core and enhanced in .NET 8 / 9, System.Guid includes explicit big-endian support:
When transmitting identifiers across networks or between microservices, serialize identifiers as canonical 36-character hyphenated strings. Strings eliminate endianness ambiguity completely.
Database differences: SQL Server vs PostgreSQL vs MySQL#
Different database management systems handle UUIDs and GUIDs according to their engineering history:
1. Microsoft SQL Server (UNIQUEIDENTIFIER)#
Microsoft SQL Server provides the native UNIQUEIDENTIFIER type, which stores 16 bytes using Microsoft's mixed-endian byte format.
Clustered index fragmentation hazard:
SQL Server uses an idiosyncratic collation order for UNIQUEIDENTIFIER. Instead of sorting from byte 0 to 15, SQL Server compares the last 6 bytes of Data4 first, then the first 2 bytes of Data4, followed by Data3, Data2, and Data1.
NEWID()generates random GUIDs, so inserts into a clustered GUID index are spread across the keyspace and may increase page splits and cache pressure.- To prevent this, SQL Server introduced
NEWSEQUENTIALID(), which produces GUIDs that sort consecutively within SQL Server's custom collation order.
2. PostgreSQL (uuid)#
PostgreSQL provides a native uuid type conforming to RFC 4122 / RFC 9562. It stores 16 bytes in big-endian network byte order and sorts them lexicographically.
- PostgreSQL natively accepts strings with or without hyphens, in uppercase or lowercase, and wrapped in braces
{...}. - For optimal write performance on large tables, read our comparison on UUID v4 vs UUID v7 to understand why time-ordered v7 keys outperform random keys.
3. MySQL and MariaDB#
MySQL has no dedicated single-purpose UUID type:
VARCHAR(36): Simple to read, but occupies 36 bytes per row plus index overhead.BINARY(16): Highly compact (16 bytes). Developers frequently useUUID_TO_BIN(uuid, 1)to swap time fields for sequential indexing when working with legacy UUID v1, or store RFC 9562 UUID v7 directly.
UUID vs GUID comparison matrix#
| Criteria | UUID (IETF / RFC) | GUID (Microsoft / .NET) |
|---|---|---|
| Ratifying Body | IETF (RFC 4122, RFC 9562) & ISO/IEC | Microsoft Corporation |
| Bit Length | 128 bits (16 bytes) | 128 bits (16 bytes) |
| Canonical String Format | 8-4-4-4-12 hyphenated (36 chars) | 8-4-4-4-12 hyphenated (36 chars) |
| Text Casing | Uppercase, lowercase, or mixed is valid | Uppercase is a historic convention |
Curly Braces {} | Outside the canonical RFC text form; accepted by some parsers | Common in Windows Registry and COM |
| Raw Byte Layout | RFC fields use network byte order | Legacy COM and default .NET byte arrays use mixed endianness |
| Versions Representable | v1 through v8 layouts defined by RFC 9562 | A Guid can hold the same 128 bits; generation APIs depend on platform version |
| Native Database Types | PostgreSQL uuid, CockroachDB uuid | SQL Server uniqueidentifier |
| Cross-Platform Text Exchange | Reliable when peers agree on accepted syntax | Reliable in canonical text form |
| Raw Binary Exchange | Define network byte order explicitly | Convert default mixed-endian arrays before RFC-order exchange |
Step-by-step workflow: Cross-platform identifier handling#
Follow this 4-step checklist to prevent identifier bugs across distributed systems:
- Format as text across network boundaries: Always transmit identifiers as 36-character canonical hyphenated strings in REST APIs, GraphQL queries, and JSON documents. Avoid sending raw 16-byte buffers unless using strict binary protocols with defined schemas (like Protocol Buffers).
- Normalize casing on ingest: Normalize incoming strings to lowercase before storing them in case-sensitive key-value stores (such as Redis or DynamoDB string keys) to avoid duplicate cache lookups.
- Strip braces before URI generation: If generating URLs, route parameters, or file paths from .NET GUIDs, strip surrounding curly braces
{}and quotes using ToolPorta's GUID Generator formatting controls. - Specify endianness explicitly in binary protocols: If you must transmit binary 16-byte payloads from C# or .NET, use
guid.TryWriteBytes(span, bigEndian: true)rather thanguid.ToByteArray().
Frequently asked questions#
Are UUID and GUID interchangeable?#
Their canonical hyphenated text usually represents the same 128-bit value. Interchange is reliable when both sides accept the same syntax and UUID variant. Braced forms, unusual variants, parser policies, and raw byte arrays still require an explicit contract.
Why does .NET reverse the first three groups of bytes?#
In the early 1990s, Microsoft defined GUID as a C structure containing three integer fields (unsigned long, unsigned short, unsigned short) and one byte array (unsigned char[8]). Because x86 architecture is little-endian, those integer fields are stored in memory with their least significant bytes first. When .NET serialized the struct directly to memory via ToByteArray(), it preserved this mixed-endian layout.
Should I store GUIDs as uppercase or lowercase in my database?#
If you use text columns, normalize to one case before comparison; lowercase is a common convention, not an RFC requirement. Prefer native UUID/GUID or 16-byte binary types where appropriate, and avoid multiple textual spellings of the same value in case-sensitive stores.
Can I insert a Microsoft GUID into a PostgreSQL uuid column?#
Yes. PostgreSQL's uuid parser is flexible. It accepts GUIDs formatted with uppercase letters, lowercase letters, or enclosed in curly braces ({...}). PostgreSQL parses the text and stores the resulting 128-bit value in canonical big-endian format.
Does GUID support modern time-ordered UUID v7?#
Yes. .NET 9 added Guid.CreateVersion7(). Its 48-bit millisecond timestamp improves index locality compared with random GUIDs, but no identifier format can promise zero fragmentation; database behavior still depends on the index and workload.
Try the related ToolPorta tools#
Ensure seamless identifier formatting and testing across your development workflow with ToolPorta's browser utilities:
- Use the GUID Generator to produce bulk GUIDs with custom braces, casing, hyphens, and prefixes tailored for .NET and Windows projects.
- Use the UUID Generator to generate RFC 9562 UUID v7 and UUID v4 identifiers for modern databases and web microservices.
- Explore the NanoID Generator for collision-resistant, URL-safe, compact string IDs.
- Read our C# GUID developer guide and equivalent JavaScript UUID examples for implementation guidance.
- Review our architectural guide on UUID v4 vs UUID v7 to optimize relational database primary key indexing.