How to Deploy a React App (Vite): Every Option Explained
A Vite React app builds into static files, so you can host it almost anywhere. How to build it, deploy to Cloudflare, Netlify, Vercel or GitHub Pages, serve it from your own server with Nginx or Caddy, fix 404s on refresh and blank pages, and handle environment variables and an API.
A React app made with Vite (which most AI builders use) is a single-page app. When you build it, it becomes a folder of plain static files — HTML, JavaScript, CSS. Deploying it means putting that folder somewhere that serves files. (What is React?, What is Vite?)
(If your app uses Next.js, see What is Next.js? and Self-hosting Next.js — it can need a server.)
Step 1: build it
npm run build
Output goes to dist/. Preview the production build locally:
npm run preview
If it fails, fix that first. (npm run build fails but dev works)
Step 2: environment variables
Variables used in the browser must start with VITE_ and are baked into the build — set them before building, on whichever machine builds.
VITE_API_URL=https://api.example.com
Anything starting with VITE_ ends up in public JavaScript, readable by anyone. Never put secret keys there. (Environment variable undefined?, Hide API keys)
Option A: a static hosting platform (easiest)
Cloudflare, Netlify, Vercel — connect your GitHub repo, set:
- Build command:
npm run build - Output directory:
dist
Every push deploys automatically, with HTTPS and a CDN. (Vercel vs Netlify vs Cloudflare Pages)
GitHub Pages — works, but needs the base path set if the site lives at /repo-name/. (GitHub Pages guide)
Option B: your own server
Copy dist/ to the server (or build it there) and serve it with Caddy:
example.com {
root * /srv/myapp/dist
try_files {path} /index.html
file_server
encode gzip zstd
}
Or Nginx:
server {
server_name example.com;
root /srv/myapp/dist;
location / {
try_files $uri /index.html;
}
}
(What is Caddy?, What is Nginx?)
The two problems everyone hits
1. 404 when you refresh a page
Visiting /dashboard directly asks the server for a dashboard file, which doesn't exist — routing happens in the browser. The server must send index.html for unknown paths. That's what try_files … /index.html does above; hosting platforms use a rewrite rule or a _redirects file. (Why refreshing gives a 404)
2. A blank page
Open DevTools → Console. Usually: JavaScript files 404ing because of a wrong base path, a missing environment variable crashing the app at start, or a runtime error. (React app shows a blank page after deploying)
What about the backend?
A React app on its own has no secure place for secrets, database access or payment logic. If your app needs those, it needs a backend too:
- Supabase or Firebase — call them from the browser, secured by their rules. (Supabase RLS)
- Serverless functions on your static host. (What is serverless?)
- Your own API (Express, FastAPI…) on a server. (Deploy an Express app)
If the API is on a different domain, you'll need CORS set up. Serving front-end and API from the same domain avoids that. (CORS errors explained)
Caching
Vite adds content hashes to file names (index-3f9a1c.js), so those can be cached for a long time. Keep index.html uncached, or users see old versions after a deploy. (Hard refresh and cache)
EasySpawn serves your React front-end and runs its API and database on the same server and domain — no CORS, no 404-on-refresh, HTTPS included. See how it works for AI-built apps or join the waitlist.
Related: React App Shows a Blank Page After Deploying · Why Refreshing Your React Page Gives a 404 · What Is Vite? · SPA vs MPA
Keep reading
robots.txt and sitemap.xml Explained: A Beginner's Guide
Two small files that tell search engines (and AI crawlers) what to crawl and what exists on your site. How robots.txt and sitemap.xml work, examples, the robots.txt mistake that hides your whole site, why Disallow doesn't remove pages from Google, and how to generate both in Next.js.
How to Add a Favicon to Your Website (HTML, Next.js, and Vite)
The small set of favicon files a modern site actually needs, the HTML tags to add, the Next.js and Vite shortcuts, the sizes Google and iPhones use, and why your new favicon still isn't showing.