Skip to content

First 5 fixes are $29 in exchange for a short testimonial.

Claim a $29 fix
Ship It Live

Guides

Supabase login redirects to localhost after deploy

Sign-in works in preview, then production sends the browser to localhost. Update the Supabase Site URL and redirect allow list, and stop sending localhost from redirectTo.

Updated 2026-10-15

The app loads, the button says Continue with Google or Send magic link, and the next page is http://localhost:3000 or http://localhost:5173. Nothing is wrong with DNS. Supabase Auth redirected to the URL it was told to use, and that URL is still the local default. The production site never gets the session, because the browser left it.

Where Supabase stores the redirect

In the Supabase dashboard, open Authentication, then URL Configuration. Two fields matter. The Site URL is the default redirect when your code does not pass redirectTo. On a new project that value is http://localhost:3000. Supabase's own redirect docs say to change it to your production URL, and they call that setting critical for email confirmations and password resets. The Redirect URLs list is the allow list. A redirectTo value has to match a pattern on that list.

Wildcards are allowed. * matches within a single path segment, and ** matches across segments, so https://your-app.vercel.app/** covers /login and /auth/callback. Supabase recommends an exact path for the production Site URL, and wildcards for local development and preview hosts. Their Vercel example adds http://localhost:3000/** and https://*-.vercel.app/** as additional redirects, while the Site URL stays on the official production origin. The Netlify example uses https://**--your-site.netlify.app/** for branch deploys.

Change the dashboard first

  1. Set Site URL to the origin people actually use, including https:// and without a trailing path unless your app really lives in a subpath. Example: https://your-app.vercel.app.
  2. Add that same origin to Redirect URLs. If callbacks use several paths, add https://your-app.vercel.app/**.
  3. Add the local dev origin you really use. For Vite that is often http://localhost:5173/**. Keep http://localhost:3000/** only if something still serves the app there.
  4. If you use Vercel preview deployments, add the documented wildcard https://*-.vercel.app/** rather than pasting one preview hostname that will change on the next push.
  5. Save. Dashboard changes apply to the next auth request. They do not rewrite emails that were already sent.

If the project has a custom domain, put that domain in the Site URL once DNS and the host both serve it. A Site URL of https://your-app.vercel.app while users sign in on https://yourdomain.com will bounce them to the vercel.app host after login, which feels like a loop even though it is not localhost.

Stop the code from sending localhost

The dashboard is only half of it. Search the repo for localhost, redirectTo, emailRedirectTo, and signInWithOAuth. A hardcoded redirectTo: "http://localhost:3000" is allowed as soon as localhost is on the list, so production happily redirects there. For a Vite app, read a public site URL with import.meta.env, and fall back to the current origin so a preview deploy still returns to itself:

function siteUrl(): string {
  const configured = import.meta.env.VITE_SITE_URL
  const raw = configured && configured.length > 0 ? configured : window.location.origin
  return raw.endsWith("/") ? raw : raw + "/"
}

const { error } = await supabase.auth.signInWithOAuth({
  provider: "github",
  options: { redirectTo: siteUrl() },
})

Set VITE_SITE_URL on the host to https://your-app.vercel.app for Production, then redeploy. Vite inlines that value at build time. A variable named NEXT_PUBLIC_SITE_URL is what Supabase's Next.js snippet uses. It does nothing in a Lovable or Bolt Vite bundle unless you also read it from import.meta.env under a VITE_ name. The same rebuild rule as the blank white screen applies: saving the variable is not enough.

Passwordless email and OAuth both take redirectTo. Magic links and signup confirmation also depend on the email template. Supabase says that when you pass redirectTo, you may need to replace {{ .SiteURL }} with {{ .RedirectTo }} in the template, or the link in the message keeps using the Site URL even after your code is correct. In Authentication, then Email Templates, open Confirm signup, Magic link, and Reset password. Point the anchor at the redirect placeholder if you rely on redirectTo.

Prove the browser stays on the production host

  1. Use a private window so an old localhost session and an old confirmation link are not in the way.
  2. Trigger a new sign-in from the production URL, not from the Lovable preview.
  3. Before you click the email link, hover it. The host should be your production domain. If it is localhost, the template or the Site URL is still wrong, or you opened a message from before the change.
  4. After OAuth, the address bar should return to the production origin, with the session established. A hop through *.supabase.co is normal. A hop to localhost is not.
  5. Repeat from /login if that is a client route. If that path 404s before auth runs, fix the SPA rewrite first. Auth cannot finish on a 404.

Provider dashboards have their own callback, which is Supabase's URL (https://<project-ref>.supabase.co/auth/v1/callback), not your localhost and not your Vercel domain. You usually do not change that when the only bug is a Site URL left on localhost. Change the Google or GitHub callback only if the provider itself rejects the Supabase callback.

Questions that come up next

I changed the Site URL and the old email still opens localhost. Why?

The link was written when the message was sent. Confirmation, magic-link, and password-reset emails keep the URL they were generated with. Request a new email after the Site URL and the redirect allow list are saved. Also check the email template: if it still uses the Site URL placeholder, update it to the RedirectTo placeholder when your code passes redirectTo.

Does the Vite dev server have to be on port 3000?

No. A new Supabase project sets the Site URL to http://localhost:3000, which is a placeholder, not a requirement. Vite's own default is http://localhost:5173. Add the origin your dev server actually prints, with a /** wildcard if you use several paths, and set the Site URL itself to the production origin.

Can I allow every Vercel preview URL?

Supabase documents a wildcard for Vercel previews: https://*-.vercel.app/** as an additional redirect URL, with the Site URL set to the real production origin. Prefer an exact production callback path for the Site URL rather than a wildcard that matches every host.