Using UUIDs in APIs — IDs, Collisions, and Best Practices
When to use UUIDs as API identifiers, v4 vs v7 trade-offs, database indexing, validation, and security pitfalls in production systems.
By Vertex Solutions Editorial
A competitor scraped our staging API and inferred launch volume from /orders/10482 and /orders/10483. Sequential integers are convenient in the database and leaky in public URLs. We switched external identifiers to UUIDs — and then spent a week tuning indexes because random v4 keys scattered inserts across B-tree pages. Identifier design is a product decision with database consequences.
Quick answer
UUIDs are 128-bit opaque identifiers — common in APIs as v4 (random) or v7 (time-ordered). Use them when you need distributed ID generation without a central allocator. Store native UUID types, validate format on input, and never treat UUIDs as secrets or session tokens.
What is a UUID in API terms?
A UUID (Universally Unique Identifier) is a 128-bit value, usually written as 36 characters with hyphens:
550e8400-e29b-41d4-a716-446655440000
Standards define versions 1–8; APIs most often use v4 (random) and increasingly v7 (timestamp-ordered). For bit layout fundamentals, see how UUIDs work.
UUIDs let clients and servers create IDs without a central allocator — useful for distributed systems, offline-first mobile apps, and public resource paths that should not reveal order or volume.
UUIDs vs auto-increment integers
| Approach | Pros | Cons | |----------|------|------| | Integer ID | Small, fast indexes, easy debugging | Predictable, exposes count, shard merge pain | | UUID | Globally unique, opaque, shard-friendly | Larger keys, index fragmentation (esp. random v4) | | ULID / Snowflake | Sortable, compact text | Extra dependency, less universal than UUID |
Public APIs often expose UUIDs so /orders/550e8400-e29b-41d4-a716-446655440000 reveals nothing about how many orders exist. Internal joins can still use integers if you maintain both columns.
UUID v4: random
Version 4 fills most bits with random data (version and variant bits set per spec). Collision probability is negligible for practical deployments — assuming a cryptographic random source, not Math.random() in a loop.
Use when: You need opaque IDs and insert order in indexes does not matter at your scale.
Watch for: Random UUID primary keys can cause index page splits in PostgreSQL, MySQL, and similar engines under heavy insert load. Mitigations include v7, sequential internal IDs with a separate public UUID column, or BRIN indexes on time-correlated columns.
Generate test values with UUID Generator during development and fixture setup.
UUID v7: time-ordered
Version 7 encodes a Unix timestamp in leading bits, improving sortability and B-tree locality while remaining opaque enough for public exposure. New services in 2026 increasingly default to v7 for primary keys when chronological log correlation matters.
Use when: You want UUID benefits plus roughly time-ordered inserts and ORDER BY id approximating creation time without a separate created_at index.
Watch for: v7 exposes coarse creation time — usually acceptable for resource IDs, unacceptable if timing metadata must stay hidden.
API design patterns
Resource paths
GET /api/orders/550e8400-e29b-41d4-a716-446655440000
PATCH /api/users/7c9e6679-7425-40de-944b-e07fc1f90ae7
Accept UUID strings in path parameters. Validate format before database lookup to avoid casting errors and timing leaks.
Client-generated IDs
Mobile and offline-first apps create UUIDs locally, sync later — no round trip waiting for server assignment. Document that clients must use standard v4 or v7, not custom strings like order_12345.
Correlation IDs
Log lines across microservices share one UUID per HTTP request for tracing. Same string format as entity IDs, different purpose — do not reuse entity IDs as trace IDs in security-sensitive audit logs without policy.
Bulk create
POST /api/items/batch may accept client UUIDs per row for idempotent retries. Server should reject duplicates within the batch and return 409 on conflict with existing primary keys.
Validation and parsing
Reject malformed IDs early:
- 32 hex digits with hyphens in 8-4-4-4-12 positions
- Case-insensitive hex (
a-f,A-F) - No braces required in JSON APIs (unlike some Windows tooling)
Test patterns in Regex Tester. Prefer language/stdlib parsers (uuid.Parse in Go, UUID type in PostgreSQL) over hand-rolled regex when available.
Do not cast unknown strings to UUID types without validation. Error messages should be generic — "Invalid request" — not "Order not found" for malformed IDs vs missing records, if that distinction leaks tenancy information.
Storage tips
- Store as native UUID type (PostgreSQL
uuid, SQL Serveruniqueidentifier) or BINARY(16) — notVARCHAR(36)— for space and format enforcement. - Index foreign keys on UUID columns used in joins; missing indexes turn UUID joins into full scans.
- Lowercase hex in JSON responses is a common convention; pick one casing and stay consistent for client cache keys.
- Avoid storing UUIDs with braces
{550e8400-...}in APIs unless legacy clients require it.
Serialization and API responses
JSON uses string UUIDs:
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"customer_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7"
}
Some drivers return binary — convert to canonical hyphenated hex for API output. Inconsistent formatting (550e8400e29b41d4a716446655440000 vs hyphenated) splits client caches and breaks string equality checks.
Inspect payloads with JSON Formatter during integration testing.
Security notes
UUIDs are identifiers, not secrets. Knowing an order UUID must not grant access if your API lacks proper authorization — enforce ownership, scopes, and session tokens on every request.
Do not use UUIDs as session tokens without additional entropy, rotation, and expiration. Use dedicated session libraries.
Base64 Encode handles binary payload transport — it does not generate or strengthen IDs.
Rate-limit ID enumeration on sensitive resources even when IDs are UUIDs. Opaque does not mean unguessable if your authorization layer is missing.
Logging and privacy
UUIDs are generally not PII alone, but combined with timestamps and IP logs they trace user journeys. Redact or hash IDs in public error reports when support bundles leave your network.
Testing and fixtures
Copy from UUID Generator for unit tests, or seed deterministic UUIDs in factories. Avoid one hardcoded UUID across every test — collisions hide integration bugs between services that assume unique IDs.
When not to use UUIDs
- Internal-only surrogate keys where integers suffice and URLs are never exposed
- Human-memorable support phone codes (
ORDER-4829) or short slugs - High-volume time-series where specialized IDs (Snowflake, ULID) outperform random UUID index behavior
- When URL length matters for SMS deep links — UUIDs are 36 characters minimum
Common mistakes
Treating UUID as authorization — Anyone with the link can access the resource. Fix with auth middleware.
v4 primary keys at billions of rows — Monitor index bloat; plan v7 or hybrid schemes before pain hits.
Client-supplied IDs without uniqueness constraints — Database unique index on id is mandatory.
Mixing UUID versions in one column — Document allowed versions; reject v1 MAC-based UUIDs if privacy policy forbids embedded hardware addresses.
Related tools
- UUID Generator — Generate v4 UUIDs for dev and testing
- JSON Formatter — Inspect API responses with UUID fields
- Regex Tester — Validate UUID format patterns
Related articles
- How UUIDs Work — Bit layout and version differences
- Understanding Regular Expressions — Pattern basics for validation
- JSON Formatting Guide — Clean API payload inspection
Key takeaways
- UUIDs hide sequence and volume better than integers — but they are not secrets.
- Random v4 fragments indexes; v7 improves insert locality while staying URL-safe.
- Validate format before lookup; generic errors prevent existence leaks.
- Native UUID storage beats varchar for space and integrity.
Conclusion
UUIDs solve distributed ID generation and opaque public URLs — at the cost of larger keys and index behavior you must plan for. Pick v4 or v7 deliberately, validate every inbound string, enforce authorization independent of ID shape, and generate test IDs with UUID Generator while your schema still fits on one whiteboard.
Frequently Asked Questions
Common questions answered to help you get the most from this tool.