React Building and Deploying Apps
Building a React app converts your development code into optimized, production-ready files. Deploying sends those files to a server so users worldwide can access the app. This topic covers the build process, environment variables, and popular deployment platforms.
Development vs Production Build
Diagram: What changes between development and production
DEVELOPMENT BUILD:
├── Source maps included (debug-friendly)
├── Error messages are verbose
├── No minification (readable code)
├── Hot module replacement active
└── Bundle size: ~2 MB+
PRODUCTION BUILD:
├── Code minified and compressed
├── Dead code eliminated (tree shaking)
├── Split into optimized chunks
├── Assets hashed for cache busting
└── Bundle size: ~100-400 KB (gzipped)
Creating a Production Build
With Vite (recommended)
npm run build
Vite outputs files to the dist/ folder:
dist/
index.html
assets/
index-abc123.js ← Main bundle (hashed filename)
index-def456.css ← CSS bundle
vendor-ghi789.js ← Third-party libraries
images/
logo-jkl012.png
The hash in the filename (like abc123) changes every time the file content changes. This busts browser cache — users always get the latest version.
With Create React App
npm run build
Output goes to the build/ folder with the same structure.
Environment Variables
Never hardcode API URLs, keys, or environment-specific values in your source code. Use environment variables to keep them separate.
Vite environment variables
# .env.development (used during npm run dev)
VITE_API_URL=http://localhost:3000/api
VITE_DEBUG=true
# .env.production (used during npm run build)
VITE_API_URL=https://api.myapp.com
VITE_DEBUG=false
// In your component — must start with VITE_
const API_URL = import.meta.env.VITE_API_URL;
const response = await fetch(`${API_URL}/users`);
Create React App environment variables
# .env
REACT_APP_API_URL=https://api.myapp.com
// In your component — must start with REACT_APP_
const API_URL = process.env.REACT_APP_API_URL;
Never commit .env files with secrets (API keys, passwords) to version control. Add .env to .gitignore and store secrets in your deployment platform's environment settings.
Deploying to Vercel
Vercel is the most popular platform for React app deployment. It detects Vite and Create React App automatically.
Step 1: Push your code to GitHub
Step 2: Go to vercel.com and sign in with GitHub
Step 3: Click "New Project" → Import your repository
Step 4: Vercel auto-detects Vite / Create React App
Build Command: npm run build
Output Directory: dist (Vite) or build (CRA)
Step 5: Add environment variables in Vercel dashboard
(Settings → Environment Variables)
Step 6: Click Deploy
└── Your app is live at: yourapp.vercel.app
Every push to the main branch triggers an automatic redeploy. Pull requests get preview URLs for testing before merging.
Deploying to Netlify
Step 1: Push code to GitHub
Step 2: Go to netlify.com → "New site from Git"
Step 3: Connect GitHub and select your repository
Step 4: Configure build settings:
Build command: npm run build
Publish directory: dist
Step 5: Add environment variables:
Site settings → Environment variables
Step 6: Click Deploy site
└── Live at: yourapp.netlify.app
Deploying to GitHub Pages
npm install --save-dev gh-pages
// package.json
{
"homepage": "https://yourusername.github.io/repo-name",
"scripts": {
"predeploy": "npm run build",
"deploy": "gh-pages -d dist"
}
}
npm run deploy
GitHub Pages serves static files from a repository. It works for React apps but has limitations — no server-side rendering and routes need special configuration for React Router.
Fixing 404 Errors on Page Refresh
React Router handles routes in the browser. When a user refreshes a page like /dashboard, the server tries to find a dashboard.html file — which does not exist. The server returns 404.
Fix this by redirecting all routes to index.html:
Netlify: add a _redirects file in public/
/* /index.html 200
Vercel: add a vercel.json file
{
"rewrites": [{ "source": "/(.*)", "destination": "/index.html" }]
}
Checking Build Size
npm run build
# Vite shows bundle sizes after build:
✓ built in 4.52s
dist/assets/index-abc.js 85.32 kB │ gzip: 28.10 kB
dist/assets/vendor-def.js 142.10 kB │ gzip: 45.80 kB
# Target: initial bundle under 200 KB gzipped
# Large bundles: add more code splitting
Performance Checklist Before Deployment
✓ Run npm run build successfully
✓ Test the production build locally: npm run preview (Vite)
✓ Check bundle size — split large chunks with React.lazy
✓ All environment variables set in deployment platform
✓ .env files added to .gitignore
✓ 404 redirect configured for React Router
✓ Error boundary added around main content
✓ App tested in Chrome, Firefox, Safari, and mobile browsers
Previewing Production Build Locally
Test the production build on your computer before deploying.
# Vite
npm run build
npm run preview
# Opens at http://localhost:4173
# Create React App
npm run build
npx serve -s build
# Opens at http://localhost:3000
Continuous Deployment
Both Vercel and Netlify support continuous deployment. Every push to the main branch automatically builds and deploys the app. Pull request branches get unique preview URLs — share them with your team to review changes before merging.
Code push to GitHub → Deployment platform detects push
→ Runs npm run build automatically
→ Deploys to production URL
→ Sends success/failure notification
Summary
Run npm run build to create a production-optimized bundle. Vite outputs to dist/ and CRA to build/. Use environment variables prefixed with VITE_ or REACT_APP_ for configuration that differs between development and production. Vercel and Netlify are the simplest deployment platforms — connect your GitHub repository and they handle the rest automatically. Fix refresh-page 404 errors with a redirect rule that points all routes to index.html. Always test the production build locally with npm run preview before shipping.
