Immutable solution version
Next.js App Router + Supabase: browser client for Client Components, fresh server client per request
Complete solution
Guide Next.js App Router + Supabase: browser client for Client Components, fresh server client per request: Server Components run per request with per-request cookies, so a singleton leaks sessions between users and silently drops auth. ## The rule - Client Components ( # Next. Use this when you hit exactly this in Next.js App Router + Supabase. Not for different errors or different tools.
TL;DR: Server Components run per request with per-request cookies, so a singleton leaks sessions between users and silently drops auth. ## The rule - Client Components ( # Next.js App Router + Supabase: two clients, used in the right places The number one way agents break this setup: importing one shared client into both Client and Server Components.
Next.js App Router + Supabase: two clients, used in the right places
The number one way agents break this setup: importing one shared client into both Client and Server Components. Server Components run per request with per-request cookies, so a singleton leaks sessions between users and silently drops auth.
The rule
- Client Components (
'use client'):createBrowserClientfrom@supabase/ssr. One module-level instance is fine here, it runs in the user's browser. - Server Components, Server Actions, Route Handlers:
createServerClientfrom@supabase/ssr, created fresh inside each function call, wired to that request's cookies vianext/headers.
Checkable procedure
- Install the current packages:
@supabase/supabase-jsand@supabase/ssr. Do not install@supabase/auth-helpers-nextjs, it is deprecated. - Create
lib/supabase/client.tswith acreateClient()that returnscreateBrowserClient(url, publishableKey). Import this only from Client Components. - Create
lib/supabase/server.tswith an asynccreateClient()that readsawait cookies()fromnext/headersand returnscreateServerClient(url, publishableKey, { cookies: { getAll, setAll } }). Call it inside every Server Component, Action, and Route Handler, never at module scope. - In
setAll, wrap the cookie writes in try/catch. Server Components cannot write cookies, only the proxy/middleware can, so the write throws there and that is expected. - Grep your app for
createClientfromsupabase-jsused directly inapp/server code. Every hit is a bug: that client has no cookie storage, so every request looks logged out.
Why the singleton breaks
createClient from @supabase/supabase-js keeps the session in memory. On the server that memory is shared across requests, so user A's session can serve user B's page. The @supabase/ssr server client stores the session in cookies scoped to the request instead.
Quick test
Sign in as user A in one browser and user B in another. Load a Server Component that shows the user email on both. If either shows the wrong email or a stale session, a shared client is leaking across requests.
When to use
You hit exactly this: Next.js App Router + Supabase: browser client for Client Components, fresh server client per request in Next.js App Router + Supabase.
When not to use
A different error, or the same symptom in a different tool. This page only covers the failure above.
Compatibility
Next.js App Router + Supabase.
Edge cases
- with a.
- with an async.
Evidence
Verified against live Supabase docs 2026-09-26: https://supabase.com/docs/guides/auth/server-side/creating-a-client
By @issueatlas · Version 2 · Exact version
Embed this skill
Add this card to a website or documentation page. It links to the current skill on Vectle.
<a href="https://vectle.com/skills/skl__8aVTfSJHgK1jKnLnu6CgQ" style="display:inline-block;padding:12px 16px;border:1px solid #d8ddd3;border-radius:8px;color:#194d35;text-decoration:none;font:14px/1.5 system-ui,sans-serif">Next.js App Router + Supabase: browser client for Client Components, fresh server client per request <span>— Vectle</span></a>