UUID formats

A UUID is a 128-bit number. That number can be represented in several ways depending on the context:

FormatExampleLengthUse case
Standard string550e8400-e29b-41d4-a716-44665544000036 charsDefault, human-readable, most APIs
Hex (no hyphens)550e8400e29b41d4a71644665544000032 charsCompact string storage, some databases
Base64VQ6EAOKbQdSnFkRmVUQAAA==24 charsJSON payloads, HTTP headers
URL-safe Base64VQ6EAOKbQdSnFkRmVUQAAA22 charsURL parameters, JWT claims
URNurn:uuid:550e8400-e29b-41d4-a716-44665544000045 charsXML, SAML, formal URI contexts
Binary16 raw bytes16 bytesDatabase storage (BINARY(16) in MySQL/SQLite)

All formats represent the exact same 128-bit value — conversion between them is lossless.

Format conversion in code

JavaScript / TypeScript

// Standard string → no-hyphen hex
function toHex(uuid: string): string {
  return uuid.replace(/-/g, '');
}

// Standard string → Uint8Array (binary)
function toBytes(uuid: string): Uint8Array {
  const hex = uuid.replace(/-/g, '');
  const bytes = new Uint8Array(16);
  for (let i = 0; i < 16; i++) {
    bytes[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
  }
  return bytes;
}

// Standard string → URL-safe Base64 (22 chars, no padding)
function toBase64url(uuid: string): string {
  const bytes = toBytes(uuid);
  const b64 = btoa(String.fromCharCode(...bytes));
  return b64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
}

// URL-safe Base64 → standard string
function fromBase64url(b64url: string): string {
  const b64 = b64url.replace(/-/g, '+').replace(/_/g, '/') + '==';
  const binary = atob(b64);
  const bytes = Uint8Array.from(binary, (c) => c.charCodeAt(0));
  const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');
  return [
    hex.slice(0, 8),
    hex.slice(8, 12),
    hex.slice(12, 16),
    hex.slice(16, 20),
    hex.slice(20),
  ].join('-');
}

// Standard string → URN
function toURN(uuid: string): string {
  return `urn:uuid:${uuid.toLowerCase()}`;
}

Python

import uuid
import base64

u = uuid.UUID('550e8400-e29b-41d4-a716-446655440000')

# Standard string (default)
print(str(u))               # 550e8400-e29b-41d4-a716-446655440000

# 32-char hex
print(u.hex)                # 550e8400e29b41d4a716446655440000

# Raw bytes (16 bytes)
print(u.bytes)              # b'\x55\x0e\x84\x00...'

# Base64 (24 chars with padding)
b64 = base64.b64encode(u.bytes).decode()
print(b64)                  # VQ6EAOKbQdSnFkRmVUQAAA==

# URL-safe Base64 (22 chars, no padding)
b64url = base64.urlsafe_b64encode(u.bytes).decode().rstrip('=')
print(b64url)               # VQ6EAOKbQdSnFkRmVUQAAA

# URN
print(u.urn)                # urn:uuid:550e8400-e29b-41d4-a716-446655440000

# Round-trip from bytes back to UUID
u2 = uuid.UUID(bytes=u.bytes)
print(u2 == u)              # True

Go

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

u := uuid.MustParse("550e8400-e29b-41d4-a716-446655440000")

// Standard string
fmt.Println(u.String())       // 550e8400-e29b-41d4-a716-446655440000

// No-hyphen hex
fmt.Println(fmt.Sprintf("%x", [16]byte(u)))  // 550e8400...

// Raw bytes (16-byte array)
bytes := [16]byte(u)

// URL-safe Base64 (no padding)
b64 := base64.RawURLEncoding.EncodeToString(bytes[:])
fmt.Println(b64)              // VQ6EAOKbQdSnFkRmVUQAAA

// URN
fmt.Println("urn:uuid:" + u.String())

Which format should I use?

Standard hyphenated string is the right default. It is human-readable, universally supported, and unambiguous. Use it for logs, API responses, and any context where a human might read the value.

Hex without hyphens is useful when column width matters and the application always controls display (e.g., internal cache keys, Redis).

URL-safe Base64 (22 chars) cuts UUID length nearly in half and is safe to put directly in a URL path or query parameter without encoding. Useful when ID length visibly affects UX (short URLs, QR codes).

Binary (16 bytes) is the most storage-efficient option and gives the best database index performance. Use BINARY(16) in MySQL/SQLite, or the native uuid type in PostgreSQL. Never use a text column for binary UUIDs — the byte order must be preserved exactly.

URN is for formal URI contexts — XML namespaces, SAML assertions, DNS-SD, or any spec that requires a URI scheme. Do not use URNs in general application code; the standard string is sufficient.

Storing the converted format in a database

MySQL / SQLite — binary storage

-- Store as 16-byte binary
CREATE TABLE events (
  id BINARY(16) PRIMARY KEY
);

-- Insert (convert string → binary in the query)
INSERT INTO events (id)
VALUES (UNHEX(REPLACE('018c4a14-2d91-7abc-8def-000000000001', '-', '')));

-- Query (convert back for display)
SELECT LOWER(HEX(id)) FROM events;

PostgreSQL — native uuid type

PostgreSQL’s uuid type stores 16 bytes internally and accepts any standard UUID string format directly — no manual conversion needed.

INSERT INTO events (id) VALUES ('018c4a14-2d91-7abc-8def-000000000001');
-- PostgreSQL normalises it to lowercase hyphenated form automatically

Frequently asked questions

What formats can a UUID be represented in?

A UUID can be represented as: the standard hyphenated string (8-4-4-4-12 hex), a 32-character hex string with no hyphens, a Base64 or URL-safe Base64 string (22 characters), a URN (urn:uuid:…), or raw 16-byte binary. The hyphenated string is the canonical form defined by RFC 9562.

Why store UUIDs as binary instead of strings?

Binary (16 bytes) is half the storage of a VARCHAR(36) UUID string (36 bytes). More importantly, binary comparison is faster than string comparison in indexes, and binary avoids encoding inconsistencies (uppercase vs lowercase). PostgreSQL's native uuid type and SQL Server's uniqueidentifier both store binary internally.

What is the UUID URN format?

The UUID URN (Uniform Resource Name) format is urn:uuid: followed by the standard hyphenated UUID, for example urn:uuid:550e8400-e29b-41d4-a716-446655440000. It is defined by RFC 9562 and used in contexts where a URI is required — such as XML namespaces, SAML, and some API specifications.