UNPKG

@crossplatformai/skills

Version:

Reusable Agent Skills for CrossPlatform.ai projects.

86 lines (58 loc) • 3.9 kB
# ID Strategy This is a Post.Build.Ship reference, not a standalone skill. Use this reference when `post`, `build`, or `ship` is already active and the work introduces or changes how an entity's ID is generated, stored, or surfaced in URLs, routes, or deep links. This reference supplements Post.Build.Ship. It preserves Authorizing User authority, observable ID contracts, material boundaries, fail-fast approvals, proportionate QA, ownership, and Ship safety. It adds no mandatory review or presentation fields. ## Decision Rule Default to `nanoid` for application-generated IDs. Use this decision rule: 1. Default: `nanoid` 2. Exception: UUIDv7 when ordered IDs are needed 3. Consider `bigint` only for purely internal database keys where DB-assigned numeric IDs are clearly the best fit 4. Do not introduce UUIDv4 as a casual default If proposing a non-`nanoid` ID for a new feature, explain why the table or entity needs ordered IDs, database-native IDs, or a separate internal/public ID strategy. ## Why `nanoid` Is The Default This workspace is cross-platform and may use entity IDs in web URLs, mobile routes, desktop navigation, deep links, and copy/pasteable identifiers. For those use cases, `nanoid` is a strong default because it is URL-safe, short, random, easy to generate on the client or server, and convenient to reuse across web, mobile, and desktop surfaces. It gives the workspace one consistent default for IDs that may become externally visible or route-safe. ## Why Not UUID By Default UUID introduces an additional design choice on every use: unordered UUIDv4 versus time-ordered UUIDv7. UUIDv4 is less attractive for write-heavy tables because it is random and not time-ordered. UUIDs are also longer and less ergonomic in URLs, routes, logs, and cross-platform navigation. UUIDv7 is still appropriate when ordered IDs are specifically needed, such as write-heavy append-oriented tables where insertion locality matters, IDs that benefit from time ordering, or distributed ID generation where ordering is useful. If ordered IDs are not needed and the ID may appear in URLs or routes, prefer `nanoid`. ## Why Not `bigint` By Default Sequential integers are useful for pure server-side database work, but they require coordination with the server. That breaks when a client needs to create a record before the server sees it. Offline-first and local-first architectures require clients to generate globally unique IDs independently. A database-assigned `bigint` cannot satisfy that requirement for client-created records. Use `bigint` only for purely internal database keys where DB-assigned numeric IDs are clearly the best fit and client-side creation, URLs, routes, deep links, and copy/pasteable identifiers are not part of the ID's job. ## Local-First Rationale In local-first and offline-first architectures, clients must assign IDs before syncing with the server. The canonical local-first pattern used in Rocicorp's Replicache examples is `nanoid()` for client-generated IDs because it is simple, short, and globally unique without coordination. ```ts await rep.mutate.createTodo({ id: nanoid(), text: 'take out the trash' }); ``` Treat that as evidence for the default, not as a requirement to use Replicache or to copy example entity names. ## Tradeoffs `nanoid` is shorter than UUID, URL-safe by default, good for routes and deep links, works well across web, mobile, and desktop, and is easy to generate without server coordination. Its tradeoffs are that it is random, not time-ordered, less ideal for append-heavy database primary keys than ordered identifiers, requires a package rather than only built-in platform APIs, and is not a native Postgres type. When those tradeoffs matter, consider UUIDv7 for ordered distributed IDs or `bigint` for purely internal database-assigned keys. Do not use UUIDv4 as the casual compromise.