Skip to content
SarvexDocs
Esc
↑↓navigate↵open⌘Jpreview
On this page

Entity ID generation: scheme selection by entity type

Different kinds of entities use different ID-generation schemes. The scheme is selected based on the entity's role and lifecycle: compound deterministic keys for tenant-scoped singletons, prefixed…

Generated from docs/adr/0008-entity-id-generation-schemes.md in the Sarvex repository — edit the source there, not this page.

Different kinds of entities use different ID-generation schemes. The scheme is selected based on the entity’s role and lifecycle: compound deterministic keys for tenant-scoped singletons, prefixed ULIDs for append-only records, prefixed nanoid for user-facing short IDs, and bare UUIDs for general-purpose resource IDs.

The codebase supports four coexisting, internally-consistent ID schemes. Each emerged to serve a specific purpose: deterministic keys ensure singular identity for aggregates that are recreated on the same tenant boundary, ULIDs provide natural ordering for audit trails, nanoid provides short user-facing identifiers, and UUID provides standard randomness for generic resources. Rather than unifying to a single scheme (which would lose useful semantic signals), the schemes are codified as a selection rule.

Scheme selection matrix

Entity type Scheme Example Rationale
Tenant-scoped singletons & aggregates Compound deterministic key readiness:store_12345:v2, checklist:store_12345, channel:store_12345:2026-08 Identity is naturally determined by tenant + version/time; recreating the entity must preserve its identity; determinism allows idempotent upserts.
Audit-log / append-only records Prefixed ULID alert_01ARZ3NDEKTSV4RRFFQ69G5FAV, ledger_01ARZ3NDEKTSV4RRFFQ70H5FAW ULID provides microsecond-precision ordering; prefix clarifies entity type in logs/traces; append-only semantics guarantee no recreations.
User-facing, short IDs Prefixed nanoid merchant_V1StGXR8_Z5j Compact, URL-safe, occasionally displayed to users; prefix disambiguates type. Merchants/store IDs fall here.
General-purpose resource IDs Bare UUID 550e8400-e29b-41d4-a716-446655440000 Standard, widely understood, sufficient randomness for resources with no special identity constraints. Stores, sessions, jobs, validation runs.

Considered options

Standardize on one scheme going forward: Use a single scheme (e.g., ULID everywhere for sortability, or UUID everywhere for simplicity) for all new entities, migrating nothing existing. Simpler decision-making for new features but loses the semantic signal that a prefixed ID currently carries about entity type and lifecycle.

Consequences

  • New entities must select their ID scheme based on the matrix above. This is a lint/review checklist item.
  • Code review should flag ID choices that don’t fit the matrix (e.g., a singleton using bare UUID, or an audit record using nanoid).
  • No migration of existing IDs is required; the four schemes coexist and are internally sound.
  • The matrix should be updated if a new entity class emerges that doesn’t fit the four categories.

Was this page helpful?