You Built a Slick Front End — and It's Stuck on localhost. Now Deploy It.
AI gave you a gorgeous front end. It only runs on localhost:3000 — a screen only you can see. Per-framework build folders, deploying to Cloudflare (static/SPA) and GAS (Sheets-backed), the 'works locally but breaks deployed' traps, and custom domains — commands included.
Bottom line first: AI built you a slick front end. And it’s at localhost:3000. That’s a screen only you, in the entire world, can see. Not deployed = not built. Two free paths: Cloudflare (static/SPA) or GAS (Google Sheets / account-backed). Five minutes and anyone opens it by link.
localhost means “only on my machine.” Deploy means “anywhere, by link.” Upload your local build output to free hosting and you’re done — it’s two steps: build, then upload the output folder.
First: where does your build output go?
Run npm run build and the static files land in one folder. The folder name differs by framework. Uploading that whole folder is the deploy.
| Framework | Build command | Output folder |
|---|---|---|
| Vite (React/Vue/Svelte) | npm run build | dist |
| Create React App | npm run build | build |
| Astro | npm run build | dist |
| Next.js (static export) | next build (output: 'export') | out |
It splits by what you built
- Static / SPA (Vite, React, Astro, Next static build) → Cloudflare Pages.
- A tool wired to Sheets / Gmail / Drive → Apps Script web app (GAS).
Path A: Cloudflare Pages (static / SPA)
npm run build # creates dist/ (or build/, out/)
npm i -D wrangler
npx wrangler login
npx wrangler pages deploy dist --project-name=my-app --branch=main
→ a https://my-app.pages.dev link, instantly. HTTPS automatic, free.
There’s also a dashboard (git-connected) way: connect a GitHub repo to Cloudflare Pages, set the build command (npm run build) and output folder (dist), and it auto-deploys on every push. Prefer that if you dislike commands.
Put env vars in the Pages settings (or wrangler vars), not in the code. But anything that reaches the front end ends up visible in the browser, so don’t put secrets there.
Path B: GAS web app (Sheets-backed)
npm i -g @google/clasp
clasp login
clasp create --type webapp --title "my-app"
clasp push
clasp deploy # issues the /exec link
The skeleton is about this much — doGet serves the screen, and google.script.run lets the front end call backend functions:
// Code.gs
function doGet() {
return HtmlService.createHtmlOutputFromFile("index");
}
function getData() {
return SpreadsheetApp.openById("SHEET_ID").getSheets()[0].getDataRange().getValues();
}
<!-- index.html -->
<script>
google.script.run.withSuccessHandler((rows) => console.log(rows)).getData();
</script>
→ runs inside your Google account, with Sheets as the DB. Zero server cost.
”Works locally, breaks deployed” — the 5 culprits
Almost everyone stalls here on day one of deploying. Suspect these in order.
Either way
- Build → upload. Build locally, ship only the output.
- Custom domain + HTTPS are free on both. Cloudflare adds a domain in the Pages settings (a few clicks if DNS is on Cloudflare); GAS attaches via Workspace or a proxy. Certificates are automatic.
- To wire it into auto-deploy → the
npm run deploy+ cron in Vibe Coding 101.
In one line
localhost:3000 is a diary only you can read. Static → Cloudflare, Sheets-backed → GAS — upload the build output for free and anyone opens it by link in five minutes. If it breaks, suspect the API address, env vars, and SPA fallback first.
Questions?
Not sure which one you built? Just ask. For the tool to build it with → So how do you actually vibe code?. The full picture → Vibe Coding 101.
Frequently asked questions
- How do I let other people see an app that runs on localhost?
- Upload your build output to free hosting. For a static site or SPA, Cloudflare Pages (wrangler pages deploy dist); for a tool wired to Google Sheets or your account, an Apps Script web app (clasp). Both give you a free link and HTTPS.
- Cloudflare or GAS — which do I pick?
- A static site or SPA (React, Vite, Astro, Next static build) goes to Cloudflare Pages. A tool that works with Google Sheets, Gmail, or Drive data goes to GAS.
- Why does it work locally but break when deployed?
- Usually one of three: an API address hardcoded to localhost, env vars not baked into the build (Vite needs a VITE_ prefix), or a 404 on SPA refresh (the host needs a _redirects fallback to index.html). Calling keys straight from the front end is another common mistake.
- Is deploying really free?
- Small scale is near zero — it runs inside Cloudflare Pages' free tier and Google's free execution quota. Heavy traffic or paid external APIs add cost accordingly.