search
React star Featured

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.

person By Gautam Sharma
calendar_today January 1, 2026
schedule 12 min read
React Deployment Vercel Netlify Frontend Development

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:

  1. Routing issues: BrowserRouter vs HashRouter configuration
  2. Build problems: Incorrect build output or missing files
  3. Path configuration: Wrong public path or base href
  4. Environment issues: Missing environment variables
  5. 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.

Gautam Sharma

About Gautam Sharma

Full-stack developer and tech blogger sharing coding tutorials and best practices

Related Articles

React

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.

January 1, 2026
React

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.

January 1, 2026
React

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.

January 1, 2026