MMakerToLaunch

Deploy

Deploy a React + Vite App for Beginners

React + Vite is one of the most common stacks in AI-generated frontends — especially from tools like Lovable, Bolt, and Cursor templates. Unlike Next.js, a standard Vite React app builds to static files in a dist/ folder. There is no Node server to run in production unless you add one. This guide explains what actually gets deployed, how to publish on Vercel or Netlify, why VITE_ environment variables behave differently from server env vars, and how to wire your frontend to a backend hosted elsewhere.

Updated July 2026 · 13 min read

Written for AI makers using tools like Cursor, Bolt, Lovable, Replit, Claude, and ChatGPT.

Quick answer

Run npm run build to produce a dist/ folder of static HTML, JS, and CSS. Deploy that folder on Vercel or Netlify (build command: npm run build, output directory: dist). Set VITE_ prefixed env vars in the host dashboard before building — they are baked into the bundle at build time. If your app calls an API, deploy the backend separately and point VITE_API_URL to its production URL.

Best for

React + Vite SPAs from Lovable, Bolt, Cursor, or create-vite

Deploy to

Vercel or Netlify (static hosting — no Node server required)

Main risk

Secrets or localhost API URLs baked into the browser bundle

What gets deployed

The dist/ folder: static HTML, JS, CSS, and assets

Who this is for

  • You have a React app created with Vite (npm create vite@latest or an AI tool) and want it online
  • You are unsure whether you need a server or just static hosting
  • Your deployed app shows a blank page, wrong API URL, or old config after changing env vars

What you'll need

  • React + Vite project on GitHub
  • Vercel or Netlify account (both have free tiers for static sites)
  • If your app uses a backend API, that API deployed somewhere with a public URL

What Vite actually builds

Vite is a development server and build tool — not a hosting platform. During development, npm run dev serves your React code with hot reload. For production, npm run build compiles everything into the dist/ directory: index.html, JavaScript bundles, CSS, and static assets like images.

That dist/ folder is a static site. A CDN serves the files to browsers. There is no server executing your React code on each request — the user's browser downloads the JS and runs it. This is called a Single Page Application (SPA) when client-side routing handles navigation after the first load.

Because the output is static, you cannot hide secrets in frontend code. Anything referenced in your React components or in import.meta.env ends up in the downloaded bundle. Plan accordingly: public API base URLs are fine; private keys are not.

If your AI tool added a backend in the same repo (Express, FastAPI, etc.), that backend does not deploy automatically with a static Vite build. You need a separate deploy for the API — usually Railway, Render, or Fly.io.

Prepare your repo for static deploy

Before connecting a host, run npm run build locally and confirm dist/ appears without errors. Fix TypeScript issues now — the host build will fail the same way.

Check vite.config.ts for a base path if your app will not live at the domain root. GitHub Pages and some subpath deploys need base: '/repo-name/'. Vercel and Netlify at the root domain usually need base: '/' (the default).

For client-side routing (React Router), you need a fallback rule so every path serves index.html. Vercel and Netlify both provide SPA redirect configs — Vite templates sometimes include a public/_redirects (Netlify) or vercel.json file. If deep links 404 in production, add the fallback.

Commit .env.example with every VITE_ variable your app reads. Add .env to .gitignore. Never push secrets — VITE_ vars are public once built.

  • npm run build creates dist/ successfully
  • vite.config.ts base path matches your deploy URL
  • SPA fallback configured for React Router deep links
  • .env.example lists all VITE_ variables

Deploy settings

Deploy on Vercel

Sign up at vercel.com, click Add New → Project, and import your GitHub repository. When Vercel asks for framework settings, choose Vite or set manually: Framework Preset Vite, Build Command npm run build, Output Directory dist, Install Command npm install (or leave default).

Add environment variables before the first deploy. Any variable your code reads via import.meta.env.VITE_SOMETHING must be set here with the VITE_ prefix. Example: VITE_API_URL=https://your-api.railway.app

Click Deploy. Vercel runs the build on its servers, uploads dist/ to its CDN, and gives you a *.vercel.app URL. Open it in incognito and test navigation to routes like /dashboard — not just the homepage.

Subsequent git pushes to main trigger automatic redeploys. Changing env vars requires a new deploy to rebuild the bundle — editing them alone does not update an already-built site.

  • Framework: Vite
  • Build command: npm run build
  • Output directory: dist
  • SPA fallback: vercel.json rewrites to /index.html

Deploy settings

Deploy on Netlify

Sign up at netlify.com and click Add new site → Import an existing project → connect GitHub. Select your repository.

Build settings: Build command npm run build, Publish directory dist. Netlify's Vite detection often fills these automatically.

Go to Site configuration → Environment variables and add each VITE_ variable. Deploy the site. Netlify shows a *.netlify.app URL when the build succeeds.

For React Router SPAs, add a _redirects file in public/ with the line /* /index.html 200 — Vite copies public/ contents into dist/ on build. Alternatively, use a netlify.toml with [[redirects]] from /* to /index.html with status 200.

Netlify and Vercel are interchangeable for basic Vite SPAs. Pick whichever dashboard you prefer — the build output is identical.

  • Build command: npm run build
  • Publish directory: dist
  • SPA fallback: public/_redirects or netlify.toml

Key concept

VITE_ environment variables (build-time, not runtime)

Vite only exposes variables prefixed with VITE_ to your client code via import.meta.env.VITE_API_URL. Unprefixed variables are ignored in the browser bundle — a safety feature, not a hosting quirk.

Critical difference from Next.js server env vars: VITE_ values are embedded at build time. When you change VITE_API_URL on Netlify, you must trigger a new build. The old bundle still contains the previous URL until redeployed.

Never put private keys in VITE_ variables. Stripe secret keys, OpenAI API keys, and database passwords belong on your backend server, not in React. If your AI template calls OpenAI directly from the browser with a VITE_OPENAI_KEY, refactor to a backend proxy before launch.

For local development, .env holds your values. For production, the host dashboard holds them. Keep .env.example updated so you do not forget a variable on deploy day.

Access pattern in code: const apiUrl = import.meta.env.VITE_API_URL. TypeScript projects often add a vite-env.d.ts reference for ImportMetaEnv.

  • Only VITE_ prefixed vars reach the browser
  • Values are baked in at build time — redeploy after changes
  • Never put secrets in VITE_ variables

Watch out

Connecting to a separate API backend

Most real apps are not frontend-only. Your React UI talks to an API for auth, data, and payments. That API runs on a different host — Railway for Django or FastAPI, Render for Node Express, Supabase for hosted Postgres + edge functions.

Set VITE_API_URL (or whatever name your code expects) to the production API base URL, including https:// and no trailing slash unless your fetch calls assume one. Rebuild the frontend after setting it.

CORS must allow your frontend domain. On the backend, configure Access-Control-Allow-Origin for https://your-app.vercel.app (or Netlify URL). AI backends often allow only http://localhost:5173 — update before launch.

Auth tokens: if using JWT or session cookies across domains, confirm cookie SameSite settings and that your auth provider lists the production frontend URL as an allowed origin.

Split deploy workflow: push backend first, get the API URL, add it as VITE_API_URL on the frontend host, then build and deploy the frontend. Testing with localhost API URLs baked into production bundles is a top beginner mistake.

  • Deploy the API first — get a public HTTPS URL
  • Set VITE_API_URL on the frontend host, then rebuild
  • Update CORS / auth callbacks for your live frontend domain

Common React + Vite deploy errors

Blank white page after deploy: open browser dev tools → Console. Usually a JavaScript error, wrong base path in vite.config, or a missing env var that makes import.meta.env.VITE_SOMETHING undefined and crashes the app.

404 on refresh for /dashboard or other routes: missing SPA fallback. Add _redirects or vercel.json rewrite to index.html.

API calls still go to localhost: VITE_API_URL was not set on the host before build, or you forgot to redeploy after changing it. Search your built dist/assets/*.js for localhost to confirm what got baked in.

CORS error in browser console: backend does not allow your frontend origin. Fix ALLOWED_ORIGINS or CORS middleware on the API server.

Old content after deploy: hard refresh (Cmd+Shift+R) or check you deployed the right branch. CDN caching is aggressive but usually not the first suspect.

Vite SPA vs Next.js — which deploy path?

If your project has vite.config.ts and no next dependency, follow this guide. If it has next in package.json, use the Next.js deploy guide instead — the env var rules and hosting defaults differ.

Vite SPAs are simpler to host (static files only) but lack server-side rendering unless you add SSR plugins. For SEO-heavy marketing pages, Next.js or a prerender step may matter. For internal tools and dashboards, static Vite deploy is often enough.

AI tools pick different stacks. Lovable and many Bolt exports use Vite + React. Cursor templates vary. Check package.json before choosing a host preset.

Vercel vs Netlify

CriteriaVercelNetlify
Build commandnpm run buildnpm run build
Output directorydistdist (Publish directory)
SPA fallbackvercel.json rewrites → /index.htmlpublic/_redirects or netlify.toml
Good forVite preset + GitHub auto-deploySimple static sites + easy redirects file

Step-by-step

  1. 1

    Step 1

    Build locally and verify dist/

    Run npm run build. Open dist/index.html structure — confirm assets compiled. Fix errors before connecting a host.

  2. 2

    Step 2

    Push to GitHub

    Ensure .env is gitignored and .env.example documents VITE_ vars. Push via GitHub Desktop, Cursor, or git.

  3. 3

    Step 3

    Deploy backend first (if applicable)

    If your app needs an API, deploy it on Railway or similar. Note the production URL for the next step.

  4. 4

    Step 4

    Import on Vercel or Netlify

    Build command: npm run build. Output/publish directory: dist. Add VITE_ env vars including VITE_API_URL if needed.

  5. 5

    Step 5

    Test routes and API calls live

    Open the live URL in incognito. Navigate to inner routes, log in, and confirm network requests hit your production API — not localhost.

Common mistakes

  • Setting API URL only in local .env and expecting production to pick it up

    What happens: The live site still calls localhost or an old URL — login and data features fail in production only.

    How to fix it: Add VITE_API_URL in Vercel or Netlify env settings, then trigger a full rebuild and redeploy.

  • Putting secret API keys in VITE_ variables

    What happens: Anyone can open DevTools, inspect the JS bundle, and copy your keys.

    How to fix it: Move secret calls to a backend. Only public URLs and publishable keys belong in VITE_ vars.

  • Wrong output directory (build instead of dist or vice versa)

    What happens: The host deploys an empty folder or the wrong files — you get a 404 or a blank site.

    How to fix it: Vite outputs to dist/ by default. Confirm in vite.config.ts — do not guess.

  • Forgetting SPA fallback for React Router

    What happens: Homepage works, but refreshing /dashboard or sharing a deep link returns 404.

    How to fix it: Add public/_redirects with /* /index.html 200 for Netlify, or equivalent vercel.json rewrites.

  • Deploying only the frontend when the repo also contains a backend

    What happens: The UI loads, but every API call fails because nothing is serving the server code.

    How to fix it: Deploy the API separately on Railway/Render. Static hosts only publish the dist/ folder.

Copy-ready prompt

Prompt: prepare React + Vite app for static deploy

Paste this into Cursor, Claude, ChatGPT, Bolt, Lovable, or your AI coding tool.

Ready to paste

I am deploying this React + Vite app to Vercel (or Netlify). Audit it for production.

1. Confirm npm run build works and output goes to dist/.
2. List every import.meta.env.VITE_* variable used. Create or update .env.example.
3. Find hardcoded localhost URLs in fetch calls or axios config — replace with env vars.
4. Check if React Router needs SPA fallback (_redirects or vercel.json).
5. Verify vite.config.ts base path is correct for root-domain deploy.
6. Identify any secret API keys exposed in frontend code and move them to a backend.
7. If there is a backend in this repo, explain how to deploy it separately and what VITE_API_URL should be.
8. List CORS or auth callback changes needed for production.

Do not commit real secrets.

Paste this into Cursor, Claude, ChatGPT, Bolt, Lovable, or your AI coding tool.

Ready check

Before you deploy

Work through these checks before you connect a host.

  • npm run build succeeds — dist/ folder created
  • .env gitignored — .env.example lists all VITE_ variables
  • Backend API deployed with public URL (if app uses an API)
  • VITE_API_URL set on host before build
  • Build command npm run build, output directory dist
  • SPA fallback configured for client-side routes
  • CORS allows frontend production domain on API
  • Live site tested — inner routes and API calls work in incognito

Frequently asked questions

Do I need a server to host a Vite React app?
No for the frontend itself — static hosting on Vercel, Netlify, or Cloudflare Pages serves dist/. You only need a server if you have a separate backend API, which deploys elsewhere.
Why do my env var changes not appear after deploy?
VITE_ variables are baked in at build time. Changing them on the dashboard requires triggering a new build, not just saving settings.
Vercel or Netlify for Vite?
Both work well for static SPAs. Settings are nearly identical: build command npm run build, output dist. Choose based on which dashboard you prefer.
What is the difference between VITE_ and NEXT_PUBLIC_?
Both mark client-visible env vars. VITE_ is for Vite projects (import.meta.env). NEXT_PUBLIC_ is for Next.js (process.env). Do not mix them — use the prefix your build tool expects.
My Lovable or Bolt app won't connect to the API — what now?
Deploy the backend first, set VITE_API_URL (or the variable your template uses) on the frontend host, rebuild, and fix CORS on the API to allow your frontend domain.