Deploying the React App to Netlify

The React Vite build produces a folder of static files โ€” index.html, JavaScript bundles, CSS, and assets. These static files do not need a Node.js server โ€” any host that can serve static files works, and a CDN (Content Delivery Network) is the best choice because it serves files from the edge server closest to the user. Netlify is a leading static hosting platform with global CDN distribution, continuous deployment from GitHub, and a generous free tier. In this lesson you will build the Vite React app for production, configure the Netlify deployment including the critical SPA fallback redirect, and set the production API URL environment variable.

Building React for Production

cd client
npm run build
# Vite creates a dist/ folder with:
# dist/index.html           โ€” main HTML entry point
# dist/assets/index-Abc123.js  โ€” bundled JavaScript (hashed filename)
# dist/assets/index-Abc123.css โ€” bundled CSS (hashed filename)
# dist/assets/...           โ€” images and other assets

# Preview the production build locally:
npm run preview
# Serves dist/ at http://localhost:4173
Note: Vite hashes asset filenames (e.g. index-Abc123.js) so browsers cache them indefinitely โ€” the hash changes when the file content changes, forcing browsers to download the new version. The index.html is not hashed โ€” Netlify serves it with short cache-control headers so users always get the latest HTML, which then references the correctly hashed JS and CSS bundles.
Tip: Run npm run build locally before pushing to Netlify and check for TypeScript or import errors. Build errors that would be silently ignored in the Vite dev server (because of HMR) often surface only at build time. Common build-time failures: a missing default export, an unused import of a type that Vite’s esbuild cannot resolve, or a Vite-env variable that is undefined at build time.
Warning: Environment variables in Vite must be prefixed with VITE_ to be included in the browser bundle. A variable without the prefix (e.g. API_URL) will be undefined at runtime in production even if you set it on Netlify. Always use VITE_API_URL and access it with import.meta.env.VITE_API_URL. Non-VITE_ prefixed variables are only available during the build process, not in the browser bundle.

The SPA Fallback Redirect โ€” Critical

Problem:
  React Router handles client-side routing โ€” /posts/123 renders PostDetailPage.
  But this route does not exist as a real file in dist/.
  When a user bookmarks /posts/123 and opens it directly:
    Browser sends GET /posts/123 to Netlify
    Netlify looks for dist/posts/123/index.html โ€” NOT FOUND
    Netlify returns 404 โ€” React Router never loads

Solution: Netlify redirect rule โ€” serve index.html for ALL paths

client/public/_redirects  (exact filename, no extension, in the public/ folder)
Contents:
  /* /index.html 200

This tells Netlify: for any path (/*), serve /index.html with status 200.
React Router then reads the URL and renders the correct component.

Alternative: netlify.toml at the project root:
  [[redirects]]
    from   = "/*"
    to     = "/index.html"
    status = 200

Deploying to Netlify โ€” Step by Step

1. Push client/ to GitHub (ensure public/_redirects is committed)

2. Go to https://app.netlify.com โ†’ Add new site โ†’ Import an existing project

3. Connect GitHub repository โ†’ select mern-blog

4. Configure build settings:
   Base directory:    client            (if monorepo)
   Build command:     npm run build
   Publish directory: client/dist       (or dist if base is set)

5. Set environment variables (Site settings โ†’ Environment variables):
   VITE_API_URL = https://mernblog-api.onrender.com

6. Click "Deploy site"
   โ†’ Netlify runs: npm run build
   โ†’ Uploads dist/ to its CDN
   โ†’ Site available at: https://random-name.netlify.app

7. Rename site (Site settings โ†’ Site details โ†’ Change site name):
   https://mernblog.netlify.app

8. Test navigation:
   โ†’ Open https://mernblog.netlify.app/posts/123
   โ†’ Should load PostDetailPage (not 404)
   โ†’ If 404: check that public/_redirects file was committed

Custom Domain (Optional)

Netlify โ†’ Site settings โ†’ Domain management โ†’ Add custom domain
  Enter: mernblog.com (or your domain)
  
Netlify provides:
  โ†’ Automatic HTTPS via Let's Encrypt
  โ†’ Global CDN distribution
  โ†’ DNS instructions for your domain registrar

DNS changes propagate in 1โ€“48 hours.
Netlify renews the SSL certificate automatically.

Netlify Build Configuration

# netlify.toml โ€” at the root of the repository (optional but useful)
[build]
  base    = "client"
  command = "npm run build"
  publish = "dist"

[[redirects]]
  from   = "/*"
  to     = "/index.html"
  status = 200

[build.environment]
  NODE_VERSION = "20"

Common Mistakes

Mistake 1 โ€” Missing the _redirects file

โŒ Wrong โ€” no redirect rule, direct navigation returns 404:

User navigates to https://mernblog.netlify.app/dashboard directly โ†’ 404 Not Found
# React Router never loads โ€” Netlify cannot find dist/dashboard/index.html

โœ… Correct โ€” create client/public/_redirects with content /* /index.html 200. Vite copies the public/ folder to dist/ during build.

Mistake 2 โ€” Not setting VITE_API_URL on Netlify

โŒ Wrong โ€” Axios uses the wrong base URL:

// import.meta.env.VITE_API_URL is undefined in production
const api = axios.create({ baseURL: undefined }); // requests go to relative path!

โœ… Correct โ€” set VITE_API_URL=https://mernblog-api.onrender.com in Netlify’s environment variables before deploying. Rebuild after adding the variable โ€” it is baked into the JS bundle at build time.

Mistake 3 โ€” Setting environment variables after the build

โŒ Wrong โ€” VITE_ variables set on Netlify after the site is already built:

Build runs โ†’ import.meta.env.VITE_API_URL = undefined (var not set yet)
Variable added to Netlify โ†’ but the old build is still deployed!
# Fix: trigger a new deploy after adding/changing VITE_ variables

โœ… Correct โ€” set Netlify environment variables before the first build, or trigger a new deploy (Deploys โ†’ Trigger deploy โ†’ Deploy site) after changing them.

Quick Reference

Task Detail
Build command npm run build
Publish directory dist (or client/dist in monorepo)
SPA fallback public/_redirects: /* /index.html 200
API URL var VITE_API_URL=https://api.onrender.com
Access in React import.meta.env.VITE_API_URL
Trigger redeploy Push to main branch or Deploys โ†’ Trigger deploy
View deploy logs Netlify Dashboard โ†’ Deploys โ†’ click the deploy

🧠 Test Yourself

Your Netlify-deployed React app works at the home page (/) but any direct URL like /posts/123 returns a Netlify 404 page. Clicking internal links works fine. What is the cause and fix?