ADR-0005: Clerk for auth, but own the users table
ADR-0005: Clerk for auth, but own the users table
- Status: Accepted
- Date: 2026-07-30
- Supersedes: —
- Superseded by: —
Context
This data model is identity-entangled: follows, feed authorship, list ownership, and the Player→User claim flow all hang off user identity. A hosted auth provider keeps the canonical user record on its own servers, synced via webhooks — a permanent failure surface.
Clerk’s free tier moved from 10,000 to 50,000 monthly retained users on 5 February 2026 (retained = returned 24h or more after signup). Cost is a non-issue at this scale, and there is existing familiarity with the tooling.
Decision
Use Clerk for authentication, but keep the canonical user record in Neon.
Clerk is the doorman, not the filing cabinet.
- Keep a
userstable in Neon with Clerk’s user ID as an external reference column (clerk_user_id). - Everything else foreign-keys to our row’s UUID, never Clerk’s ID directly.
- Create the local row lazily on first authenticated request. Do not write code that depends on a webhook having fired first.
Consequences
- Migrating to Better Auth or anything else later becomes a one-table swap rather than a rewrite.
- Webhook delivery failures degrade rather than break: the lazy-create path is the primary mechanism, webhooks are reconciliation.
- Every schema review must check that no new table foreign-keys to
clerk_user_id. - MFA and passkeys are Clerk Pro features; social login and the prebuilt UI are free.
- Clerk stores user data in the US with no EU data-residency option. Irrelevant at friends-and-family scale; revisit if UK/EU usage grows.
Note on stale sources
A great deal of published material — and many models’ training data — still quotes the 10,000-user free tier. The current figure is 50,000 MRU. Check source dates before repeating tier numbers.