Websites

Supabase Login Works Locally but Not on Vercel? 8 Fixes

Supabase authentication works locally but fails on Vercel? Check environment variables, redirect URLs, Site URL, Preview domains, cookies, and redeployment.

Ryan Lee9 min read
Supabase Login Works Locally but Not on Vercel? 8 Fixes

A Supabase login flow can work perfectly on localhost and then fail the moment the app is deployed to Vercel.

That happened to me while moving from local development into real Preview and Production deployments.

The confusing part is that several different problems can produce almost the same symptom:

  • login appears to succeed but the user returns to the wrong page
  • OAuth works locally but not on a Preview URL
  • email confirmation links return to localhost
  • password reset opens the wrong domain
  • Supabase variables are missing in Preview
  • the browser never keeps the expected session
  • an old deployment is still using old configuration

The answer is not always "fix the login code."

I now debug the flow by separating the layers.

Quick answer: check these 8 things

If Supabase login works locally but not on Vercel, check:

  1. Confirm the correct Supabase environment variables exist in Vercel.
  2. Make sure the variables are available to the failing environment: Preview or Production.
  3. Redeploy after changing environment variables.
  4. Set the Supabase Site URL to the real production URL.
  5. Add the required Vercel Preview URLs to Supabase Redirect URLs.
  6. Make sure your code sends an allowed redirectTo URL.
  7. Check whether cookies/session handling work correctly in the deployed environment.
  8. Test the exact new deployment, not an older Preview URL.

Most of the time, the failure is not one mysterious authentication bug.

It is a mismatch between the application URL, Vercel environment, and Supabase Auth configuration.

1. Check the Supabase variables in Vercel

Start with the simplest question.

Does the failing Vercel deployment actually have the Supabase configuration it needs?

A current public Next.js client may use:

NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=sb_publishable_...

The exact variable names depend on your code.

That is important.

If the code reads:

process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY

but Vercel stores:

NEXT_PUBLIC_SUPABASE_ANON_KEY

the application still sees the expected variable as missing.

Compare the code and Vercel settings directly.

2. Check Preview vs Production scope

A very common situation looks like this:

  • localhost works
  • Production works
  • Vercel Preview fails

The code may be fine.

The required variables may be enabled only for Production.

Vercel separates its standard environments into:

  • Development
  • Preview
  • Production

A pull request or non-production branch usually creates a Preview deployment.

If authentication fails only there, check the Preview variable scope before changing application logic.

I explain the environment difference in more detail in Vercel Preview vs Production Environment Variables Explained.

3. Redeploy after changing variables

Changing an environment variable in the Vercel dashboard does not retroactively rebuild an existing deployment.

After changing a variable:

  1. save it
  2. create a new deployment
  3. wait for the build to complete
  4. test the new URL

This is easy to miss when several Preview deployments exist.

You can fix the configuration correctly and still think it failed because you are testing an older deployment.

4. Set the Supabase Site URL correctly

In Supabase Auth URL Configuration, the Site URL is the default redirect destination when your code does not provide another allowed redirect.

For a production application, set it to the real production site.

For example:

https://www.example.com

Do not leave the production Site URL as:

http://localhost:3000

if real users are authenticating on the deployed site.

This setting matters for flows such as:

  • email confirmation
  • password reset
  • magic-link login
  • OAuth fallback redirects

Supabase's current documentation describes the Site URL as critical for email confirmations and password resets.

5. Add allowed Redirect URLs for Preview deployments

The Site URL alone is not enough when you intentionally want authentication to return to multiple environments.

Supabase also has a Redirect URLs allow list.

If your application passes a redirectTo value during authentication, that destination must match an allowed URL.

For local development, you might allow:

http://localhost:3000/**

For Vercel Preview deployments, Supabase supports wildcard patterns such as:

https://*-your-team-slug.vercel.app/**

Use the pattern that matches your actual Vercel Preview URLs.

For Production, Supabase recommends an exact production URL rather than an unnecessarily broad wildcard.

That gives you flexibility for previews without making the production rule vague.

6. Check the redirect URL your code is actually sending

The Supabase dashboard can be configured correctly while the application still sends the wrong destination.

For OAuth, OTP, password reset, or email confirmation flows, inspect the URL used by the code.

For example:

await supabase.auth.signInWithOAuth({
  provider: "google",
  options: {
    redirectTo: callbackUrl,
  },
})

The important question is:

What is callbackUrl on this deployment?

Locally, it may be:

http://localhost:3000/auth/callback

In Production:

https://www.example.com/auth/callback

In Preview:

https://feature-branch-your-team.vercel.app/auth/callback

If the generated URL is not on the Supabase Redirect URLs list, the flow may not return where you expect.

7. Use the deployment URL intentionally

Supabase's current Vercel guidance mentions using a production site URL together with Vercel's deployment URL variables for environment-aware redirects.

A common approach is to prefer:

  1. your explicit production site URL
  2. the current Vercel deployment URL
  3. localhost as the development fallback

The exact implementation depends on your framework and application.

The principle is more important:

Do not hard-code localhost into a redirect helper that also runs in Production.

And do not assume a generated Preview hostname is identical to your production hostname.

If the redirect appears correct but the user is immediately treated as logged out, the problem may be session handling rather than the redirect allow list.

In server-rendered Next.js applications, Supabase authentication often involves cookies so the server and browser can share session state.

Check:

  • are auth cookies being written?
  • are they available on the domain you expect?
  • is server-side Supabase code reading them correctly?
  • is middleware or a callback route refreshing the session where required?
  • is any cache serving a response that should be user-specific?

Supabase's SSR guidance specifically warns about caching responses that contain refreshed session cookies, because cached authenticated responses can create serious session problems.

This is a different class of issue from environment variables.

Treat it separately.

How I separate the failure by symptom

Login button does nothing

Check:

  • browser errors
  • Supabase client configuration
  • missing public variables

Login opens provider but returns to the wrong site

Check:

  • Site URL
  • Redirect URLs
  • redirectTo
  • Production vs Preview URL generation

Works in Production but not Preview

Check:

  • Preview environment variables
  • Preview redirect wildcard
  • branch-specific configuration
  • new deployment after changes

Check:

  • Supabase Site URL
  • explicit redirect target in the reset request

Redirect works but user appears logged out

Check:

  • callback/session exchange
  • cookies
  • SSR client setup
  • caching
  • domain mismatch

This prevents me from treating every auth problem as the same bug.

A practical Next.js URL helper

The exact code varies by project, but the idea is to produce the correct base URL for the environment.

For example:

export function getSiteUrl() {
  const explicit = process.env.NEXT_PUBLIC_SITE_URL

  if (explicit) {
    return explicit.endsWith("/") ? explicit : `${explicit}/`
  }

  const vercelUrl = process.env.NEXT_PUBLIC_VERCEL_URL

  if (vercelUrl) {
    return `https://${vercelUrl}/`
  }

  return "http://localhost:3000/"
}

Then the auth flow can construct the callback from that base URL.

This is an example pattern, not a requirement.

The key is to understand which URL the deployed app is generating.

Production redirect configuration

For the live application, I prefer explicit values.

Example:

Supabase Site URL

https://www.example.com

Allowed Production Redirect

https://www.example.com/**

Or an even narrower callback path if your application only needs one.

Exact rules are easier to reason about and safer to maintain.

Preview redirect configuration

For previews, a wildcard can be practical because every deployment may receive a generated hostname.

Supabase documents a Vercel Preview pattern like:

https://*-<team-or-account-slug>.vercel.app/**

Use your real team/account slug and verify that the pattern matches your deployment URLs.

Do not copy a placeholder pattern without checking it.

Do not expose Supabase secret keys to fix auth

When authentication fails, it can be tempting to try a more powerful key.

Do not solve browser authentication by placing a Supabase secret key or legacy service_role key in a NEXT_PUBLIC_ variable.

Public client authentication should use a publishable key.

Authorization and data security should be enforced with:

  • authenticated user identity
  • database grants
  • Row Level Security
  • trusted server-side code for privileged operations

Authentication troubleshooting should not weaken the application's security model.

My Supabase + Vercel login checklist

  • [ ] The failing deployment uses the expected Vercel project.
  • [ ] Supabase variable names match the application code.
  • [ ] Preview has the variables required by Preview.
  • [ ] Production has the variables required by Production.
  • [ ] A new deployment was created after environment changes.
  • [ ] Supabase Site URL is the real production URL.
  • [ ] Local redirect URLs are allowed only where needed.
  • [ ] Preview redirect patterns match the actual Vercel hostname.
  • [ ] Production redirects use the intended production domain.
  • [ ] The application's redirectTo value matches an allowed URL.
  • [ ] Session cookies work after the callback.
  • [ ] Server-side auth code is not being incorrectly cached.
  • [ ] No privileged secret is exposed to the browser.

FAQ

Why does Supabase login work locally but not on Vercel?

The deployed environment may be missing Supabase variables, using a different redirect URL, testing an old deployment, or handling sessions differently from localhost.

Why does Supabase redirect back to localhost?

Check the Supabase Site URL and the explicit redirectTo value used by the application. A production project should not rely on localhost as its default redirect.

How do I support Vercel Preview URLs in Supabase?

Add an appropriate wildcard pattern to Supabase Redirect URLs that matches your Vercel Preview hostname structure.

Why does Supabase login work in Production but not Preview?

Preview may have different environment variables and a different hostname. Check both the Vercel Preview variable scope and the Supabase redirect allow list.

Should I use a secret Supabase key for login?

No. Browser clients should use the publishable key. Secret or privileged keys belong only in trusted server-side code.

Final thoughts

The biggest change in my debugging process was learning not to call every failed login an authentication-code problem.

A deployed login flow crosses several systems:

Browser → application → Vercel environment → Supabase Auth → redirect URL → session → application again

A failure at any of those boundaries can look like "Supabase login is broken."

Now I check the boundaries one by one.

That is much faster than rewriting a working login flow blindly.

For the broader environment-variable troubleshooting process, read Vercel Environment Variables Not Working? 7 Supabase Fixes.

For the backend architecture behind authentication and permissions, see Why Use Supabase for a Web App? Auth, RLS & Real Project Lessons.

Practical AI. Real Experience. Built in Public.

#Supabase#Vercel#Authentication#Redirect URLs#Next.js#Preview Deployment#Troubleshooting
Share

Related reading

More practical notes are coming

The newsletter will open once the email system is ready. Until then, new articles are published directly on the blog.

Newsletter coming soon

Email signup will appear here once the mailing system is ready.