TIC Association
Next.js · Supabase · Vercel

Works on localhost, breaks in production.

Your local run and your production deployment differ in five places: the public variables the browser bundle was built with, the URL sign-in returns to, the cookies a server route reads, which key runs where, and whether the hosted database got your migrations. Check them in this order and the cause is usually the first one that fails.

the symptom

Same code, two different environments.

npm run dev, localhost:   works
vercel production:        500, a blank page, "Invalid API key", or sign-in that lands on localhost

What is different in production? Not your code. A production build freezes the public variables into the bundle, the deployment runs with the variables that existed when it was built, sign-in returns to whatever URL your project allows, and a server route only knows the user if the request's cookies reach it. Each of those is a setting, and each has a primary source below.

find your cause

Five checks. In this order.

1

The public variables were not there when the bundle was built

Anything the browser needs, such as your Supabase URL and publishable key, is prefixed NEXT_PUBLIC_, and Next.js says what that does: "it will be inlined into any JavaScript sent to the browser." And the consequence: "variables will be frozen with the value evaluated at build time, so these values need to be set appropriately when the project is built." So a variable added to the dashboard after the build is not in the bundle. Vercel: "Any change you make to Environment Variables are not applied to previous deployments, they only apply to new deployments." Check: the same names as in your .env.local exist for the Production environment, then redeploy.

Vercel project > Settings > Environment Variables > Production
NEXT_PUBLIC_SUPABASE_URL              set
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY  set       then: Deployments > Redeploy
2

Sign-in comes back to localhost

Magic links and OAuth return the user to the URL the project allows, and a project that only ever knew http://localhost:3000 sends production users there. Supabase: "we recommend setting the exact redirect URL path for your site URL in production." Check: the Site URL is your production domain and the production callback path is in the redirect allow list.

3

A server route has no session

Locally you were signed in through the browser; in production a server component, route handler or middleware built a client with no cookies, and the database saw nobody. Supabase: "Server-Side Rendering (SSR) with Supabase requires cookie-based session storage." Then every policy that compares auth.uid() fails, inserts get 42501 and selects come back empty. Proven on a real PostgreSQL and explained on the auth.uid() page.

4

The wrong key in the wrong place

The publishable key belongs in the browser and runs under row level security. The secret key belongs on the server only, and even there it does not always bypass policies. Supabase: "A secret key bypasses RLS only when the request carries no user access token." Check: no secret key in any NEXT_PUBLIC_ variable, and the server code that needs to bypass policies is not forwarding the user's token.

5

The hosted database never got the migration

If local development runs against a local database, the table, column or policy you added there does not exist on the hosted project until your migration is applied to it. Check: open the hosted project's SQL editor and confirm the table and its policies are there; if row level security is on with no policy, every request is refused, which is the 42501 page.

questions

Straight answers.

Do I have to redeploy after adding an environment variable on Vercel?
Yes. Vercel's documentation says changes to environment variables are not applied to previous deployments and only apply to new deployments, and Next.js inlines public variables into the bundle at build time.
Why does sign-in send production users to localhost?
Because the project's Site URL or redirect allow list still points at localhost. Supabase recommends setting the exact redirect URL path for your site URL in production.
Which Supabase key goes in the browser?
The publishable key, which runs under row level security. The secret key stays on the server, and it bypasses row level security only when the request carries no user access token.

Still broken after the five checks? Send us the error.

The free diagnosis reads the cause from your error and gives you the fix path in about a minute. No repo access, no card. If it needs hands-on work, one blocker is scoped and you pay only after it works.

Get the free diagnosis

Checking policies on the hosted project? The free RLS auditor lists the holes worst first in about a minute.

The diagnosis lives at rescue.ticassociation.com; paste the error text and the stack you built with.

© 2026 TIC Association Privacy · Terms hello@ticassociation.com