

Ed Morales
Product
5
min read
Dec 31, 2025
Supabase's move to JWT Signing Keys (asymmetric JWT signing + JWKS) is one of those upgrades that hits the rare trifecta: better security, smoother operations, and faster apps.

What made it feel like a developer's dream wasn't just the technical change, it was the whole experience: the docs are clear, the rollout is built for real-world migrations, and the platform makes key rotation feel boring (in the best way).
If you haven't read them yet, start here:
The parts that impressed us the most:
1) Migration without fear
The biggest "wow" is that Supabase designed this so you can migrate and rotate without breaking everyone's sessions:
Dual compatibility during migration: you can keep existing JWT behavior working while you adopt the new signing keys flow.
Rotation without downtime: rotate keys, keep existing (non-expired) tokens valid, and move forward safely.
Operational fallback: in practice, this means you can ship support for the new keys first, rotate second, and still have a clean escape hatch.
That sequencing matters. It's what makes it feel safe to do in production.
And the best part? If you do it right, the migration is… boring. It's almost anticlimactic: you deploy support for the new keys, rotate, and nothing explodes. That's not luck, that's a well-designed migration path.
2) Performance that's easy to actually use
The docs and examples make it clear that the new model enables local verification via signing keys / JWKS, which reduces the need for round-trips just to "learn who the user is".
In a Next.js App Router world, that's huge:
Middleware and Server Components can run a lot.
If every request path requires a network verification call, you pay for it in latency and reliability.
If you can safely verify claims locally for most paths, things get snappier fast.
Supabase's getClaims() approach is what made the "fast path" feel ergonomic, not risky.
What the performance gains look like in practice
Here's what you typically win when you shift routine auth checks to claims verification:
Fewer network round-trips on the "every request" paths (middleware, layout gating, server components).
Lower tail latency: fewer dependencies on a remote auth verification call when you just need identity/claims to render.
More resilient UX: fewer "auth hiccups" where a transient network issue turns into "logged out" UI.
Cleaner layering: use the fast path for "who are you?", keep the verified path for "are you allowed to do this?".
In Next.js, that's the difference between auth being a constant tax and auth being basically invisible.
Check out this great tutorial video for a complete breakdown
As usual, Jon Meyers from Supabase put together a great video tutorial to demystify the process and show you exactly how easy it is:
The auth setup we recommend in Next.js
Dreambase's auth strategy became intentionally hybrid:
API Routes: use DB-verified auth (
supabase.auth.getUser()) for authorization-critical operations (mutations, permission-gated reads).Middleware / Server Components / Server Actions: use a fast, claims-based helper backed by
supabase.auth.getClaims().
1) Env vars: prefer new keys, keep legacy fallbacks (during migration)
On the client, accept either the new publishable key or the anon key as a fallback:
On the server, we prefer the new secret key, with service-role as fallback:
This is the exact "both sets of keys work" property you want during rollout and rotation.
2) Fast path: getClaims() → typed "authenticated user"
Create a tiny helper that turns JWT claims into the minimal user object you need to render UI and gate routes.
And we reused it in middleware to avoid doing heavier auth work just to decide whether someone is authenticated to see a route:
3) Security still matters: API routes stay DB-verified
For the parts of the app that mutate data and enforce RBAC, we kept the stronger, DB-verified call in API routes:
That "fast path where safe, verified path where required" split is the real win in practice.
Recommended migration checklist (practical + low drama):
Based on the Supabase rollout model:
Enable JWT Signing Keys in Supabase and read through the rotation/migration steps (signing keys guide).
Ship code that supports the new keys first:
Add
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY(client/shared).Add
SUPABASE_SECRET_KEY(server-only).Keep
NEXT_PUBLIC_SUPABASE_ANON_KEYandSUPABASE_SERVICE_ROLE_KEYas fallbacks until you're confident.
Separate auth "fast path" from "verified path":
Use claims-based helpers (
getClaims()) for UI gating and non-critical user hydration.Keep DB verification (
getUser()) for API routes and sensitive mutations.
Rotate keys when your deployments are live and stable, then monitor.
Only then revoke the legacy secret once you're satisfied everything is issuing/verifying as expected.
Why this felt like a "developer's dream"
The standout is that Supabase treated this like a production migration, not a breaking change:
Great docs + concrete workflow
Amazing tutorial videos that are incredibly easy to follow
Migration and rotation designed around compatibility and confidence
A very practical path to performance wins in modern frameworks
If you're building on Nextjs and Supabase, this upgrade is one of the few that genuinely feels like: "ship it, rotate it, forget it."
A key rotation shouldn't be a launch. It should be a boring Tuesday maintenance task you barely remember.
Ready to witness a new world in AI-native analytics where YOU take the driver's seat?






