No articles found
Try different keywords or browse our categories
Fix: Blank page after deploying React app on Vercel / Netlify - Complete Guide
Learn how to fix blank page errors when deploying React apps on Vercel and Netlify. This guide covers routing, build issues, and deployment best practices.
The ‘blank page after deploying React app on Vercel/Netlify’ error is a common issue that React developers face when deploying their applications. This error typically occurs due to routing configuration issues, incorrect build settings, or problems with the production build process. The application works perfectly in development but shows a blank page when deployed.
This comprehensive guide explains what causes this error, why it happens, and provides multiple solutions to fix it in your React deployments with clean code examples and directory structure.
What Causes the Blank Page Error?
The blank page error occurs when the deployed React application fails to load properly due to:
- Routing issues: BrowserRouter vs HashRouter configuration
- Build problems: Incorrect build output or missing files
- Path configuration: Wrong public path or base href
- Environment issues: Missing environment variables
- CORS problems: Cross-origin resource sharing issues
Understanding the Problem
When your React app works locally but shows a blank page after deployment, it’s usually due to differences between the development and production environments:
- Local development: Uses development server with hot reloading
- Production deployment: Serves static files from a CDN or web server
- Routing differences: Client-side vs server-side routing
- Asset paths: Different base paths for assets
Typical React Project Structure:
my-react-app/
├── package.json
├── public/
│ ├── index.html
│ └── favicon.ico
├── src/
│ ├── App.jsx
│ ├── index.js
│ ├── components/
│ │ └── MyComponent.jsx
│ └── routes/
│ └── Router.jsx
├── build/ (after npm run build)
└── .vercel/ (for Vercel) or .netlify/ (for Netlify)
Solution 1: Fix React Router Configuration (BrowserRouter vs HashRouter)
The most common cause is using BrowserRouter in a static hosting environment.
❌ Before (Causing Blank Page):
// src/App.jsx
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import Home from './components/Home';
import About from './components/About';
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</BrowserRouter>
);
}
export default App;
✅ After (Fixed for Static Hosting):
// src/App.jsx
import { HashRouter, Routes, Route } from 'react-router-dom';
import Home from './components/Home';
import About from './components/About';
function App() {
return (
<HashRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</HashRouter>
);
}
export default App;
Install HashRouter:
npm install react-router-dom
Solution 2: Configure Custom 404 Page for BrowserRouter
If you want to keep BrowserRouter, configure proper 404 handling.
For Netlify (_redirects file):
# public/_redirects
/* /index.html 200
For Vercel (vercel.json):
{
"rewrites": [
{ "source": "/(.*)", "destination": "/" }
]
}
For Netlify (netlify.toml):
[[redirects]]
from = "/*"
to = "/index.html"
status = 200
Solution 3: Fix Public Path Configuration
Ensure the correct public path is set in package.json.
❌ Before (Incorrect):
{
"name": "my-react-app",
"homepage": ".",
"private": true,
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
}
✅ After (Fixed):
{
"name": "my-react-app",
"homepage": ".",
"private": true,
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
}
}
For Subdirectory Deployment:
{
"homepage": "https://yourdomain.com/subdirectory/",
"private": true
}
Solution 4: Update index.html Base Tag
Add or update the base tag in your index.html file.
public/index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta name="description" content="Web site created using create-react-app" />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
-->
<base href="./">
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
Solution 5: Check Build Process and Console Errors
Step 1: Verify Build Process
# Clean previous builds
rm -rf build/
# Create new build
npm run build
# Check build output
ls -la build/
Step 2: Check Browser Console
Open browser developer tools and check the Console tab for errors:
- JavaScript errors
- Missing assets
- Network errors
- React errors
Step 3: Check Network Tab
Look for failed requests to:
- JavaScript files
- CSS files
- Images
- API endpoints
Solution 6: Environment Variables Configuration
Ensure environment variables are properly configured for production.
❌ Before (Development Only):
// src/config/api.js
const API_URL = process.env.REACT_APP_API_URL || 'http://localhost:3000';
✅ After (Production Ready):
// src/config/api.js
const API_URL = process.env.REACT_APP_API_URL || 'https://api.yourdomain.com';
// Ensure VITE_ prefix for Vite projects
const VITE_API_URL = import.meta.env.VITE_API_URL || 'https://api.yourdomain.com';
Environment Files:
# .env.production
REACT_APP_API_URL=https://api.yourdomain.com
REACT_APP_ENV=production
Solution 7: Fix Asset Loading Issues
Ensure assets are properly referenced in production.
❌ Before (Relative Paths):
// components/Logo.jsx
function Logo() {
return <img src="logo.png" alt="Logo" />; // ❌ May not work in production
}
✅ After (Public URL):
// components/Logo.jsx
function Logo() {
return <img src="%PUBLIC_URL%/logo.png" alt="Logo" />; // ✅ Works in production
}
// Or using import
import logo from '../assets/logo.png';
function Logo() {
return <img src={logo} alt="Logo" />;
}
Solution 8: Vercel-Specific Configuration
vercel.json:
{
"version": 2,
"builds": [
{
"src": "package.json",
"use": "@vercel/static-build",
"config": {
"distDir": "build"
}
}
],
"routes": [
{
"src": "/(.*)",
"dest": "/index.html"
}
]
}
For Next.js Projects:
{
"rewrites": [
{
"source": "/(.*)",
"destination": "/"
}
]
}
Solution 9: Netlify-Specific Configuration
netlify.toml:
[build]
publish = "build"
command = "npm run build"
[[redirects]]
from = "/*"
to = "/index.html"
status = 200
[context.production.environment]
REACT_APP_API_URL = "https://api.yourdomain.com"
_redirects file (public/_redirects):
# SPA redirect
/* /index.html 200
Solution 10: Check for React Errors
Add error boundaries to catch React-specific errors.
src/components/ErrorBoundary.jsx:
import React from 'react';
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false, error: null, errorInfo: null };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
this.setState({
error: error,
errorInfo: errorInfo
});
// Log error to an error reporting service
console.error('React Error:', error, errorInfo);
}
render() {
if (this.state.hasError) {
return (
<div>
<h2>Something went wrong.</h2>
<details style={{ whiteSpace: 'pre-wrap' }}>
{this.state.error && this.state.error.toString()}
<br />
{this.state.errorInfo.componentStack}
</details>
</div>
);
}
return this.props.children;
}
}
export default ErrorBoundary;
Usage in App.jsx:
// src/App.jsx
import ErrorBoundary from './components/ErrorBoundary';
import { HashRouter, Routes, Route } from 'react-router-dom';
function App() {
return (
<ErrorBoundary>
<HashRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</HashRouter>
</ErrorBoundary>
);
}
Solution 11: Optimize Build for Production
package.json:
{
"name": "my-react-app",
"homepage": ".",
"private": true,
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.8.0"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"predeploy": "npm run build",
"deploy": "gh-pages -d build"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
Complete Project Structure After Fix
my-react-app/
├── package.json
├── vercel.json (for Vercel) or netlify.toml (for Netlify)
├── public/
│ ├── index.html
│ ├── favicon.ico
│ ├── manifest.json
│ └── _redirects (for Netlify)
├── src/
│ ├── App.jsx
│ ├── index.js
│ ├── components/
│ │ ├── ErrorBoundary.jsx
│ │ └── MyComponent.jsx
│ └── routes/
│ └── Router.jsx
├── build/ (generated after build)
└── .gitignore
Working Code Examples
Complete App Setup for Static Hosting:
// src/App.jsx
import React from 'react';
import { HashRouter, Routes, Route } from 'react-router-dom';
import ErrorBoundary from './components/ErrorBoundary';
import Home from './components/Home';
import About from './components/About';
import Contact from './components/Contact';
function App() {
return (
<ErrorBoundary>
<HashRouter>
<div className="App">
<nav>
<a href="#/">Home</a>
<a href="#/about">About</a>
<a href="#/contact">Contact</a>
</nav>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} />
</Routes>
</div>
</HashRouter>
</ErrorBoundary>
);
}
export default App;
Production-Ready Index.js:
// src/index.js
import React from 'react';
import { createRoot } from 'react-dom/client';
import './index.css';
import App from './App';
import * as serviceWorkerRegistration from './serviceWorkerRegistration';
const container = document.getElementById('root');
const root = createRoot(container);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
serviceWorkerRegistration.unregister();
Best Practices for Deployment
1. Use HashRouter for Static Hosting
// ✅ For static hosting (Vercel, Netlify)
<HashRouter>
// ❌ For server hosting
<BrowserRouter>
2. Test Production Build Locally
# Build and serve locally
npm run build
npx serve -s build
3. Verify Environment Variables
// ✅ Check environment variables
console.log('Environment:', process.env.NODE_ENV);
console.log('API URL:', process.env.REACT_APP_API_URL);
4. Use Proper Error Handling
// ✅ Add error boundaries and logging
<ErrorBoundary>
<App />
</ErrorBoundary>
Debugging Steps
Step 1: Check Console Errors
# Open browser dev tools and check Console tab
# Look for JavaScript errors, network errors, or React errors
Step 2: Verify Build Output
# Check if build files exist
ls -la build/
cat build/index.html
Step 3: Test Locally
# Serve build locally to test
npx serve -s build
# Visit http://localhost:3000
Step 4: Check Network Requests
# In browser dev tools, check Network tab
# Look for failed requests to JS, CSS, or other assets
Common Mistakes to Avoid
1. Using BrowserRouter on Static Hosting
// ❌ Don't use BrowserRouter on Netlify/Vercel without proper configuration
<BrowserRouter>
// ✅ Use HashRouter or configure proper redirects
<HashRouter>
2. Incorrect Public Path
// ❌ Wrong for static hosting
"homepage": "https://yourdomain.com"
// ✅ Correct for static hosting
"homepage": "."
3. Missing Redirects
<!-- ❌ No redirect configuration -->
<!-- ✅ Add redirect configuration for BrowserRouter -->
Performance Considerations
1. Optimize Bundle Size
# Analyze bundle size
npm install --save-dev webpack-bundle-analyzer
npm run build
npx webpack-bundle-analyzer build/static/js
2. Lazy Loading
// Use lazy loading for better performance
import { lazy, Suspense } from 'react';
const LazyComponent = lazy(() => import('./LazyComponent'));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
);
}
Security Considerations
1. Validate Environment Variables
// ✅ Validate environment variables
if (!process.env.REACT_APP_API_URL) {
console.error('API URL is not configured');
}
2. Sanitize User Input
// ✅ Sanitize user input before using in routing
const sanitizedPath = sanitizePath(userInput);
navigate(sanitizedPath);
Testing Deployment
1. Local Production Test
# Build and test locally
npm run build
npx serve -s build
2. Staging Deployment
# Deploy to staging environment first
# Test all functionality before production
3. Browser Testing
# Test in different browsers
# Test different screen sizes
# Test network conditions
Alternative Solutions
1. Use Server-Side Hosting
# Host on a server that supports server-side routing
# Instead of static hosting
2. Configure Custom Server
// Express server with proper routing
const express = require('express');
const path = require('path');
const app = express();
app.use(express.static(path.join(__dirname, 'build')));
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
Migration Checklist
- Update routing to use HashRouter or configure redirects
- Set correct homepage in package.json
- Add base tag to index.html if needed
- Test production build locally
- Check console for errors
- Verify all assets load correctly
- Test all routes work properly
- Update environment variables for production
Conclusion
The ‘blank page after deploying React app on Vercel/Netlify’ error is typically caused by routing configuration issues when using BrowserRouter on static hosting platforms. By using HashRouter, configuring proper redirects, or setting the correct public path, you can resolve this error and ensure your React applications work correctly in production.
The key solutions include choosing the right router for your hosting environment, configuring proper redirects, testing production builds locally, and implementing proper error handling. With these fixes in place, your React applications will deploy successfully and provide a seamless user experience.
Remember to always test your production builds locally before deploying and use proper error boundaries to catch any issues that might occur in the production environment.
Related Articles
Fix: Invalid React hook call. Hooks can only be called inside of the body of a function component
Learn how to fix the 'Invalid hook call' error in React. This guide covers all causes, solutions, and best practices for proper React hook usage with step-by-step examples.
Fix: Module not found: Can't resolve 'react/jsx-runtime' - Complete Solution Guide
Learn how to fix the 'Module not found: Can't resolve react/jsx-runtime' error in React projects. This guide covers causes, solutions, and prevention strategies with step-by-step instructions.
Fix: npm ERR! ERESOLVE unable to resolve dependency tree in React Projects
Learn how to fix the 'npm ERR! ERESOLVE unable to resolve dependency tree' error in React projects. This guide covers causes, solutions, and best practices for dependency management.