top of page
AI App Rescue / Deploy

Works in the preview. Breaks after deploy.

The most common failure across every AI builder, and the one that catches everybody. Your app ran perfectly thirty seconds ago and now it's a white screen, a login loop, or an error that names nothing.

Nothing you did was wrong

You spent weeks building it. It worked. Every feature you tested did what it was supposed to do, right up until the moment you pressed deploy.


Then: a build that fails with "check logs" and a log that says nothing. Or a deploy that succeeds and serves a blank page. Or users who log in successfully and land straight back on the login screen.


So you changed something and redeployed. Then something else. You've now done that enough times that you're not sure what state the project is in, and each round takes longer than the last.


Your code is almost certainly fine. Nothing in the repository changed between the version that worked and the version that doesn't. What changed is where it's running — and that's a much shorter fix than it feels like right now.


Here's the part nobody tells you.



The preview is designed to make things work. Production isn't.


That sentence is the whole page.


Your builder's preview environment runs with credentials, environment variables, database connections and permissions handed to it automatically. That's exactly what makes building feel fast — you never had to configure any of it, because the preview configured it for you.


Production has only what you explicitly gave it. Every assumption the preview quietly satisfied becomes a failure the moment you deploy.


Two things make this hard to diagnose:

The errors describe the symptom, not the gap. A missing environment variable doesn't say "missing environment variable." It says the build failed, or the page is blank, or the API returned 500. You're given the consequence and left to infer the cause.


Nothing in your code changed, so the natural next move is to prompt about it. That cannot work. Lovable, Bolt, Cursor and Replit can all read your code, and your code is not where the problem is.


So what's actually going on?



What you see, and what's usually behind it

Find your symptom, then read the detail underneath.

What you see

What's usually wrong

Build fails with a generic message

Missing environment variable at build time, or a dependency not in the lockfile

Deploys successfully, page is blank

Frontend runtime error the build never caught — check the browser console

Login succeeds, then bounces to login

Production domain missing from the auth provider's redirect URL list

"Failed to fetch" on every API call

CORS blocking your own domain, or an API base URL still pointing at localhost

500 on every backend request

Missing secret, or a database the deployment can't reach

Nothing saves

Connection string pointing at a development project, or one that was deleted

Stripe or OpenAI calls fail silently

API key absent from production, error swallowed rather than surfaced

Hydration mismatch in the console

Server and client rendering different output — dates, randomness or browser-only code

Images and assets 404

Paths that resolved relative to the preview and don't on a real host

Custom domain doesn't load

DNS, SSL provisioning, or the domain never added to the hosting project

Env var changes have no effect

Value read at build time and baked in — needs a rebuild, not a restart

Worked yesterday, broken today

Expired credential, floating dependency version, or a provider-side change



The eight causes underneath


  • Environment variables that exist in the builder and not in production. The most common cause by a wide margin. Either the build fails outright, or it succeeds and every external call — Supabase, Stripe, OpenAI, SendGrid, Firebase — fails silently at runtime.


  • Auth redirect URLs pointing at the preview domain. In Supabase this is the Site URL and Redirect URLs list. In Google OAuth it's the authorised redirect URI. In Clerk or Auth0 it's the allowed callback. Login itself works; the session is discarded on the way back.


  • Database credentials scoped to development only. The app connects to a Postgres, Supabase or Neon project that exists for development, or to nothing at all. Migrations that ran in development never ran in production, so the schema doesn't match what the code expects.


  • Build-time versus runtime configuration. Anything prefixed NEXT_PUBLIC_, VITE_ or similar is read at build time and baked into the bundle as whatever it was when you deployed. Changing it afterwards changes nothing until you rebuild. This one produces the maddening "I updated it and it didn't help."


  • CORS and allowed origins never updated. The browser blocks requests from your production domain to your own API. The console says so clearly. The build log says nothing at all, which is why people miss it for hours.


  • Hardcoded URLs left from development. localhost:3000 in production code. Obvious the moment you see it, invisible until then, and AI builders generate it routinely because it's correct while you're building.


  • No error boundary. A single runtime failure in one component blanks the entire page rather than that component. This is what most white screens actually are — not a deploy failure, a rendering failure with nothing to catch it.


  • DNS, SSL and domain configuration. The last step and the most common cause of downtime during a launch, because it's usually left until everything else is done and then rushed.


Before you contact anyone — four of these you can check yourself.



Four checks, in this order

Most cases resolve at one of them, and we'd rather you didn't pay us for that.

1. Compare your environment variables Open your builder's variables list next to your hosting provider's. Not from memory — side by side. Anything present in one and missing from the other is your answer more often than not.


2. Check your auth redirect URLs In Supabase: Authentication → URL Configuration. Your production domain needs to be in both the Site URL and the Redirect URLs list. In Google Cloud Console it's under your OAuth client's authorised redirect URIs. The preview domain being there is not enough.


3. Open the browser console on the live site Press F12, go to Console, reload. Not the build log — the browser console. The real error is almost always sitting there in one line, and it usually names the exact thing that's missing.


4. Confirm the database exists Check that the project your production connection string points at is real, current, and not your development one. Then check whether your migrations actually ran against it.


If those four don't resolve it, something else is going on.



When to stop redeploying


  • You've been on the same failure for more than two hours. Past that you're not converging on a fix — you're accumulating changes and moving away from a known-good state.


  • You can't say what's changed since it last worked. That's the point where each new attempt makes diagnosis harder rather than easier.


  • The app is live and users are affected. Experimentation now has an hourly cost, and the arithmetic has changed.


There's a quieter signal too: you've started making changes you don't understand, because something on the internet suggested them. That's usually the moment an outside reader is the fastest route out.


Here's what that looks like.



We reproduce it in production, not on a laptop


That distinction matters more than it sounds. A local copy is a third environment with its own gaps — fixing something locally tells you almost nothing about why production fails.


An engineer reads the code, the build configuration and both environments side by side, and reproduces the failure where it's actually happening. Once reproduced, the cause is usually unglamorous and quick.


The work that matters is what comes next. If one environment gap exists, others almost always do, and they're sitting there waiting for your next deploy. We find those before they surface, which is the difference between fixing this failure and fixing this class of failure.

You get a working deployment, a written note on what was wrong, and a list of everything else that would have broken next.


What we won't do

  • Hardcode a value to make the deploy pass. That's how this becomes a worse problem in six weeks.

  • Fix one variable and leave the rest unchecked.

  • Rewrite anything that was already working.


One thing worth saying about what this is costing you.



The gap compounds quietly


Every failed deploy is time, and if you're building with a metered AI tool it's also credits — spent on a problem the tool structurally cannot solve, because the fault isn't in the code it can read.


Meanwhile the launch date moves, the customer who was going to see it this week doesn't, and the codebase accumulates changes made under pressure that nobody documented.


None of that is a reason to panic. It is a reason to stop and have someone read it, rather than deploying a fourteenth time.


Which builder you used changes where it bites.



By tool

The gap is universal. Its favourite hiding place isn't.

Tool

Where it usually goes wrong

Lovable

Supabase connection and auth redirects. The preview works because you're logged in and the redirect list has the preview domain. Production has neither.

Netlify deploys failing on a missing Supabase anon key, with a build error that names nothing useful.

Replit

Secrets set in the workspace and never carried into the deployment, plus host binding to localhost.

v0

API routes that work locally and fail in production, and hydration mismatches that only appear once rendered on a server.

Cursor

Environment configuration assumed rather than checked, because the model had no way to see your hosting setup.

Base44

Third-party keys never promoted out of development, and deployment configuration left at defaults.



How a rescue runs


01 — Audit. You send the repository. An engineer reads the code, the build config and both environments, and comes back within 48 hours with what's broken and what else is waiting. Free.


02 — Reproduce. The failure confirmed in your actual production environment, not assumed from an error message.


03 — Fix. The real cause, delivered as a change you can read.


04 — Sweep. Every other environment gap found and closed before your next deploy finds it for you.


05 — Separate. Staging made genuinely distinct from production, so the next release is testable before it's live.


06 — Handover. What was wrong, what changed, and a deploy process that doesn't do this again. You own it.


Step five is the one that ends the problem permanently. The gap exists because there was nowhere to catch it.



Questions


Which builders does this apply to? All of them. Lovable, Bolt, Replit, v0, Cursor, Base44, Windsurf. Previews exist to make building easy, and that's precisely what creates the gap.


It deployed successfully but the page is blank. Usually a runtime error the build never caught. The browser console will name it in one line; the build log won't mention it at all.


It worked yesterday and I changed nothing. An expired credential, a floating dependency version, or a provider-side change. All three are common, none are your fault, and all are quick to confirm.


Do I need to move off the builder to fix this? No. This is configuration, not architecture. If moving is genuinely right for other reasons, we'll say so separately rather than bundling it into a deploy fix.


Can you set up staging so this stops happening? Yes, and it's usually the most valuable part of the engagement. The gap exists because there's nowhere to catch it before users do.


I changed the environment variable and nothing happened. If it's a build-time variable, the old value is baked into the bundle. It needs a rebuild, not a restart.


Will you sign an NDA? Yes, mutual, before you send anything. One senior engineer reads your code, it's never used for training, and access is removed after delivery.


My app is live and users are affected right now. Tick the box on the form. Live incidents jump the queue.



Send us the repository

You'll get what's actually failing, what else would have failed on the next deploy, and what it takes to make production predictable.


Request the audit



Also broken?


Supabase · Authentication · Lovable · Bolt.new · Replit · The AI keeps breaking working code · Security audit




bottom of page