<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Gaurang Dobariya</title>
    <description>The latest articles on DEV Community by Gaurang Dobariya (@gaurangdobariya).</description>
    <link>https://dev.to/gaurangdobariya</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4145221%2Ffc9fb66b-6143-40b7-a3ec-7941b13a4a45.jpeg</url>
      <title>DEV Community: Gaurang Dobariya</title>
      <link>https://dev.to/gaurangdobariya</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gaurangdobariya"/>
    <language>en</language>
    <item>
      <title>Your Lovable or Bolt app works in preview but breaks after deploy? 5 common causes and fixes</title>
      <dc:creator>Gaurang Dobariya</dc:creator>
      <pubDate>Sun, 27 Sep 2026 08:10:45 +0000</pubDate>
      <link>https://dev.to/gaurangdobariya/your-lovable-or-bolt-app-works-in-preview-but-breaks-after-deploy-5-common-causes-and-fixes-5h50</link>
      <guid>https://dev.to/gaurangdobariya/your-lovable-or-bolt-app-works-in-preview-but-breaks-after-deploy-5-common-causes-and-fixes-5h50</guid>
      <description>&lt;p&gt;You built your app with Lovable, Bolt, Replit or Cursor. In the preview everything works. You deploy it to Vercel or Netlify, open the live link and get a &lt;strong&gt;blank screen&lt;/strong&gt;, a &lt;strong&gt;404&lt;/strong&gt;, or a &lt;strong&gt;login that sends users to &lt;code&gt;localhost&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The good news: it's almost never your whole app that's broken. Most AI-built apps are React + Vite (often with Supabase), and they tend to fail after deploy for the same few reasons.&lt;/p&gt;

&lt;p&gt;Here are the 5 I see most often, and how to fix each one.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Environment variables exist on your machine, not on the host
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Symptoms:&lt;/strong&gt; blank screen, &lt;code&gt;supabaseUrl is required&lt;/code&gt;, API calls to &lt;code&gt;undefined/...&lt;/code&gt;, or features that silently do nothing.&lt;/p&gt;

&lt;p&gt;Your project probably reads config like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;supabaseUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;VITE_SUPABASE_URL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;supabaseKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;VITE_SUPABASE_ANON_KEY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Locally, those values come from your &lt;code&gt;.env&lt;/code&gt; file. But &lt;code&gt;.env&lt;/code&gt; is (correctly) not pushed to GitHub, so &lt;strong&gt;your host has no idea what they are.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open your &lt;code&gt;.env&lt;/code&gt; file and copy each variable name and value.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vercel:&lt;/strong&gt; Project → Settings → Environment Variables. &lt;strong&gt;Netlify:&lt;/strong&gt; Site configuration → Environment variables.&lt;/li&gt;
&lt;li&gt;Add each variable with the &lt;strong&gt;exact same name&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redeploy.&lt;/strong&gt; This step matters: Vite bakes these values into your code &lt;strong&gt;at build time&lt;/strong&gt;, so adding them without rebuilding changes nothing.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Two rules while you're there:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In Vite, only variables starting with &lt;code&gt;VITE_&lt;/code&gt; are available in the browser. &lt;code&gt;SUPABASE_URL&lt;/code&gt; won't work; &lt;code&gt;VITE_SUPABASE_URL&lt;/code&gt; will.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Never put secret keys in a &lt;code&gt;VITE_&lt;/code&gt; variable.&lt;/strong&gt; Everything with that prefix ends up in public JavaScript that anyone can read. With Supabase, the &lt;strong&gt;anon key&lt;/strong&gt; is designed to be public; the &lt;strong&gt;service_role key must never be in your frontend.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. Refreshing any page except the homepage gives a 404
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Symptoms:&lt;/strong&gt; the homepage loads fine, clicking around works, but refreshing &lt;code&gt;/dashboard&lt;/code&gt; or sharing a link to &lt;code&gt;/login&lt;/code&gt; shows &lt;strong&gt;404 Not Found&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Your app is a single-page app. There is only one real file, &lt;code&gt;index.html&lt;/code&gt;, and React Router handles the URLs in the browser. When you refresh &lt;code&gt;/dashboard&lt;/code&gt;, the server looks for a file called &lt;code&gt;dashboard&lt;/code&gt;, doesn't find one, and returns 404.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix: tell the host to always serve &lt;code&gt;index.html&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vercel:&lt;/strong&gt; create &lt;code&gt;vercel.json&lt;/code&gt; in the project root:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rewrites"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/(.*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"destination"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/index.html"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Netlify:&lt;/strong&gt; create &lt;code&gt;public/_redirects&lt;/code&gt; containing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight apache"&gt;&lt;code&gt;&lt;span class="err"&gt;/*&lt;/span&gt;    &lt;span class="err"&gt;/&lt;/span&gt;index.html   200
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Commit, push, and refreshing any page will work.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Login redirects to localhost (or fails after sign-in)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Symptoms:&lt;/strong&gt; users sign up or log in and land on &lt;code&gt;http://localhost:3000&lt;/code&gt; / &lt;code&gt;localhost:5173&lt;/code&gt;. Magic links and password-reset emails point to localhost. Google login shows a "redirect URL not allowed" error.&lt;/p&gt;

&lt;p&gt;Your auth provider still thinks your app lives on your laptop.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix (Supabase):&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Supabase dashboard → &lt;strong&gt;Authentication → URL Configuration&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Set &lt;strong&gt;Site URL&lt;/strong&gt; to your live domain, e.g. &lt;code&gt;https://yourapp.vercel.app&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Redirect URLs&lt;/strong&gt;, add your live domain (and keep &lt;code&gt;http://localhost:5173&lt;/code&gt; if you still develop locally)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you use Google or GitHub login, also add the live URL in that provider's OAuth settings.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. The frontend still calls &lt;code&gt;localhost&lt;/code&gt; for the API
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Symptoms:&lt;/strong&gt; works on your machine, but on the live site the network tab shows requests to &lt;code&gt;http://localhost:5000/...&lt;/code&gt; failing, or CORS errors.&lt;/p&gt;

&lt;p&gt;AI tools often hardcode the backend address while you're developing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:5000/api/orders&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That works on your laptop because your backend runs there. On a visitor's phone, &lt;code&gt;localhost&lt;/code&gt; means &lt;em&gt;their&lt;/em&gt; phone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Deploy the backend separately (Render, Railway, etc.) and get its URL.&lt;/li&gt;
&lt;li&gt;Replace hardcoded URLs with an environment variable:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;API_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;VITE_API_URL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;API_URL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/api/orders`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Add &lt;code&gt;VITE_API_URL&lt;/code&gt; on your frontend host (see cause #1) and redeploy.&lt;/li&gt;
&lt;li&gt;On the backend, allow your live frontend in CORS, e.g. with Express:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;cors&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://yourapp.vercel.app&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  5. The build fails on the server but works locally
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Symptoms:&lt;/strong&gt; the deploy log shows &lt;code&gt;Could not resolve "./components/Header"&lt;/code&gt; or &lt;code&gt;Module not found&lt;/code&gt;, even though the file obviously exists.&lt;/p&gt;

&lt;p&gt;Very often this is &lt;strong&gt;letter case&lt;/strong&gt;. Windows and macOS usually treat &lt;code&gt;Header.tsx&lt;/code&gt; and &lt;code&gt;header.tsx&lt;/code&gt; as the same file. Vercel and Netlify build on Linux, where they are &lt;strong&gt;different files&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Header&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./components/Header&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// file is actually header.tsx&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; make every import match the file name exactly, including capital letters.&lt;/p&gt;

&lt;p&gt;If you renamed a file only by changing its case, Git may not have noticed. Rename it properly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git &lt;span class="nb"&gt;mv &lt;/span&gt;src/components/header.tsx src/components/Header.tsx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Other quick checks when the build fails:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run &lt;code&gt;npm run build&lt;/code&gt; locally. If it fails there too, the error message tells you which file is broken.&lt;/li&gt;
&lt;li&gt;Make sure the &lt;strong&gt;build command&lt;/strong&gt; is &lt;code&gt;npm run build&lt;/code&gt; and the &lt;strong&gt;output directory&lt;/strong&gt; is &lt;code&gt;dist&lt;/code&gt; (for Vite).&lt;/li&gt;
&lt;li&gt;If the log mentions TypeScript errors, the AI may have left type errors that preview mode tolerated but the production build doesn't.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Quick checklist before every deploy
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] All &lt;code&gt;.env&lt;/code&gt; variables added on the host, then &lt;strong&gt;redeployed&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;[ ] No secret keys in &lt;code&gt;VITE_&lt;/code&gt; variables&lt;/li&gt;
&lt;li&gt;[ ] SPA rewrite added (&lt;code&gt;vercel.json&lt;/code&gt; or &lt;code&gt;_redirects&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;[ ] Auth Site URL and Redirect URLs point to the live domain&lt;/li&gt;
&lt;li&gt;[ ] No &lt;code&gt;localhost&lt;/code&gt; left in API calls&lt;/li&gt;
&lt;li&gt;[ ] &lt;code&gt;npm run build&lt;/code&gt; passes locally&lt;/li&gt;
&lt;li&gt;[ ] Import paths match file names exactly, including case&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Still stuck?
&lt;/h2&gt;

&lt;p&gt;These 5 cover most of the "works in preview, broken in production" problems I see, but AI-generated code can fail in creative ways. If your app still won't behave, drop your error in the comments and I'll try to point you in the right direction.&lt;/p&gt;

&lt;p&gt;And if you'd rather have someone fix and deploy it for you, I do exactly that for apps built with Lovable, Bolt, Replit and Cursor: &lt;a href="http://www.fiverr.com/s/ZomZjxa" rel="noopener noreferrer"&gt;fix bugs&lt;/a&gt; · &lt;a href="http://www.fiverr.com/s/7jYBPLW" rel="noopener noreferrer"&gt;deploy with your domain&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>supabase</category>
      <category>vercel</category>
    </item>
  </channel>
</rss>
