ProdVerdict
← Blog
BillingJune 30, 20262 min read

Stripe Entitlements migration checklist (before you cut over)

Moving from Postgres paid flags to Stripe Entitlements? Pitfalls, dual-write traps, and how to verify billing vs DB before you flip the switch.

stripe entitlements migrationstripe entitlements syncbilling source of truthhas_paid_access migrationstripe entitlements webhooksaas billing migration

Stripe Entitlements can be the billing source of truth for feature access. Your app probably still has has_paid_access, is_pro, or plan in Postgres from before the migration.

The cutover week is when drift hurts most. Two systems think they own access. Neither is wrong until they disagree.

Before you migrate

QuestionWhy it matters
Which rows are paid in DB but missing in Entitlements?Orphan paid users lose access on cutover
Which Entitlements grants have no DB mirror yet?New subscribers may bypass your legacy gates
Are webhooks wired for entitlements.active_entitlement_summary.updated?Without it, Entitlements changes do not reach your app

WorkOS documents the sync problem: Stripe tracks billing entitlements, but your app must persist and serve them. Missed webhook handling = stale access.

Dual-write trap

Teams often run:

  1. Write Entitlements on checkout
  2. Also flip is_pro in Postgres
  3. Plan to remove step 2 later

"Later" is where bugs live. Step 2 stops updating when someone edits a subscription in the Stripe dashboard. Step 1 fails silently when a webhook returns 200 without writing.

Run both sides until a verifier says they match. ProdVerdict ships an entitlements-migration contract for exactly that comparison.

$
npx prodverdict check entitlements-migration

Guide: Entitlements migration.

Cutover checklist

  1. Inventory — export active Stripe subs + DB paid flags + Entitlements grants
  2. Map features — each product feature → entitlement lookup key → DB column or role
  3. Wire webhooks — entitlement summary updates, not just invoice.paid
  4. Verify — run migration contract daily until zero high-severity findings
  5. Flip reads — app checks Entitlements (or synced table) as primary
  6. Keep reconcile — scheduled Access check for stragglers on legacy columns

After cutover

Do not delete the reconcile job. Entitlements can be correct while your cached table is stale. Scheduled drift detection catches the gap.

Related:

— mattbaconz

Try it in 60 seconds

Run the fixture demo — no Stripe key or database required.

$fixture demo
npx prodverdict@latest check access --config examples/nextjs-stripe/prodverdict.yml --fixtures --fixtures-dir examples/nextjs-stripe/scenarios/fail-revenue-leak

Comments

Guest comments. No account required. Max 300 words.

Loading comments…

0/300 words