<?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: Infrly</title>
    <description>The latest articles on DEV Community by Infrly (@infrly).</description>
    <link>https://dev.to/infrly</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%2F4165862%2Fa8c1b1c7-73b7-4aae-bc5f-4ee889ae16e9.png</url>
      <title>DEV Community: Infrly</title>
      <link>https://dev.to/infrly</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/infrly"/>
    <language>en</language>
    <item>
      <title>Your AI-built app works locally but breaks when you deploy it? Check these 6 things</title>
      <dc:creator>Infrly</dc:creator>
      <pubDate>Tue, 06 Oct 2026 10:35:11 +0000</pubDate>
      <link>https://dev.to/infrly/your-ai-built-app-works-locally-but-breaks-when-you-deploy-it-check-these-6-things-37cb</link>
      <guid>https://dev.to/infrly/your-ai-built-app-works-locally-but-breaks-when-you-deploy-it-check-these-6-things-37cb</guid>
      <description>&lt;p&gt;You built an app with Cursor, Claude Code, Lovable or Bolt. On your laptop it's perfect. You deploy it, and you get a blank page, a &lt;code&gt;502&lt;/code&gt;, or a login button that spins forever.&lt;/p&gt;

&lt;p&gt;We run a small deployment platform, so we watch a lot of first deploys. Most of the failures we see happen before the app even starts, and the causes repeat. None of them mean the AI wrote bad code. They're the gap between "runs on my laptop" and "runs on a server", and AI tools rarely close that gap for you.&lt;/p&gt;

&lt;p&gt;Here are the six we see most, with the fix for each.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The frontend still calls &lt;code&gt;localhost&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;While you built the app, the API ran on your machine, so the AI wired the frontend to it:&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;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&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:3000/api/todos&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;In production, &lt;code&gt;localhost&lt;/code&gt; means &lt;em&gt;the visitor's own computer&lt;/em&gt;. Every request fails, and the browser console fills with &lt;code&gt;ERR_CONNECTION_REFUSED&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; read the API address from configuration and set it per environment.&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;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="c1"&gt;// e.g. https://api.example.com&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&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/todos`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Frontend variables are baked in when you build
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;VITE_…&lt;/code&gt;, &lt;code&gt;NEXT_PUBLIC_…&lt;/code&gt; and &lt;code&gt;REACT_APP_…&lt;/code&gt; variables aren't read at runtime. They're copied into your JavaScript at build time. If you add or change one on the server after the build, nothing happens.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; set them &lt;em&gt;before&lt;/em&gt; the build runs on your hosting platform, then rebuild and redeploy.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. The server listens on the wrong address or port
&lt;/h2&gt;

&lt;p&gt;This works on your laptop:&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="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On a hosting platform, your app has to listen on all interfaces and on the port the platform gives it, usually in the &lt;code&gt;PORT&lt;/code&gt; variable. Otherwise the platform's health check can't reach it, and the deploy fails or times out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&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;PORT&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0.0.0.0&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Python / FastAPI&lt;/span&gt;
uvicorn main:app &lt;span class="nt"&gt;--host&lt;/span&gt; 0.0.0.0 &lt;span class="nt"&gt;--port&lt;/span&gt; &lt;span class="nv"&gt;$PORT&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. The database didn't come with you
&lt;/h2&gt;

&lt;p&gt;Locally you had a SQLite file or a Docker Postgres with your test data. In production there's an empty database, or none at all, and your tables don't exist yet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; create a production database, set &lt;code&gt;DATABASE_URL&lt;/code&gt; to it, and run your migrations against it, either as part of the deploy or once by hand:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"postgres://…"&lt;/span&gt; npx prisma migrate deploy
&lt;span class="c"&gt;# or: alembic upgrade head&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5. CORS blocks the frontend
&lt;/h2&gt;

&lt;p&gt;Frontend on &lt;code&gt;app.example.com&lt;/code&gt;, API on &lt;code&gt;api.example.com&lt;/code&gt;: the browser refuses the API's responses unless the API says that origin is allowed. The error looks like a network failure, which makes it confusing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; allow your frontend's production domain in the API's CORS settings. If you use cookies, list the exact domain instead of &lt;code&gt;*&lt;/code&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="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://app.example.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  6. Secrets ended up in the frontend
&lt;/h2&gt;

&lt;p&gt;Anything in frontend code is public: anyone can open the browser's dev tools and read it. To "make it work", AI tools sometimes put a service key or a third-party API key straight into the frontend.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; keep secrets on the server and call third-party APIs from your backend. If you use Supabase, only the &lt;em&gt;anon&lt;/em&gt; key belongs in the frontend, and Row Level Security must be on for every table. In 2025, a missing-RLS pattern exposed user data in more than 170 AI-built apps (&lt;a href="https://www.superblocks.com/blog/lovable-vulnerabilities" rel="noopener noreferrer"&gt;CVE-2025-48757&lt;/a&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  The 60-second checklist
&lt;/h2&gt;

&lt;p&gt;Before your first deploy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] No &lt;code&gt;localhost&lt;/code&gt; left in frontend code&lt;/li&gt;
&lt;li&gt;[ ] Frontend variables set &lt;em&gt;before&lt;/em&gt; the build&lt;/li&gt;
&lt;li&gt;[ ] Server listens on &lt;code&gt;0.0.0.0&lt;/code&gt; and &lt;code&gt;$PORT&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;[ ] &lt;code&gt;DATABASE_URL&lt;/code&gt; set and migrations run&lt;/li&gt;
&lt;li&gt;[ ] CORS allows your production domain&lt;/li&gt;
&lt;li&gt;[ ] No secrets in the frontend bundle&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your deploy still fails, read the build log from the top, not the bottom. The first error is usually the real one; everything after it is fallout.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;What broke your first deploy?&lt;/strong&gt; Tell us in the comments. We'll add the common ones to this list.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;We build &lt;a href="https://getinfrly.com/?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=six_things" rel="noopener noreferrer"&gt;Infrly&lt;/a&gt;, which deploys GitHub repos as web services, static sites, cron jobs, PostgreSQL and Key Value, and is free during its public beta. This list comes from watching first deploys fail. This article was written with AI assistance and checked by us.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>automation</category>
      <category>ai</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
