search
React star Featured

How to Solve React Blank Page After Deploy & Build Error Tutorial

Learn how to fix React blank page errors after deployment. Complete guide with solutions for production builds and deployment optimization.

person By Gautam Sharma
calendar_today January 1, 2026
schedule 13 min read
React Deployment Production Error Handling Build Optimization

The React blank page after deploy error is a common issue developers face when their React application appears empty or blank after deployment. This problem occurs due to various factors including build configuration issues, asset loading problems, and environment-specific code.

This comprehensive guide provides complete solutions to resolve the blank page error with practical examples and deployment optimization techniques.


Understanding the Blank Page Error

React applications may appear blank after deployment due to several reasons:

  • Asset loading failures (CSS, JS files not loading)
  • JavaScript errors preventing app initialization
  • Incorrect public path configuration
  • Environment variable issues
  • Build optimization problems
  • CORS and security policy violations

Common Symptoms:

  • White/blank screen after deployment
  • Console errors related to assets or modules
  • App container exists but no content renders
  • JavaScript errors preventing initialization

Common Causes and Solutions

1. Asset Loading Issues

The most common cause is assets not loading properly in production.

❌ Problem Scenario:

// This works locally but fails after deploy due to incorrect paths
function BadAssetComponent() {
  return (
    <div>
      {/* ❌ Relative paths may break after deploy */}
      <img src="./assets/logo.png" alt="Logo" />
      <link rel="stylesheet" href="./styles/main.css" />
    </div>
  );
}

✅ Solution: Use Public URL and Proper Paths

// Correct approach - use public URL for assets
function GoodAssetComponent() {
  return (
    <div>
      {/* ✅ Use public URL for assets */}
      <img src={`${process.env.PUBLIC_URL}/logo.png`} alt="Logo" />
      {/* ✅ Or import directly */}
      <img src={logoImage} alt="Logo" />
    </div>
  );
}

// Import images properly
import logoImage from './assets/logo.png';

// For CSS, ensure it's properly imported in index.js
// import './styles/main.css';

2. JavaScript Errors in Production

Errors that don’t appear in development can cause blank pages in production.

❌ Problem Scenario:

// This might work in development but fail in production
function BadComponent() {
  const [data, setData] = useState(null);

  useEffect(() => {
    // ❌ This might fail in production due to API differences
    fetch('/api/data')
      .then(response => response.json())
      .then(setData);
  }, []);

  // ❌ This will cause issues if data is null
  return <div>{data.items.map(item => <p key={item.id}>{item.name}</p>)}</div>;
}

✅ Solution: Proper Error Handling

// Correct approach - handle errors and null states
function GoodComponent() {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        setLoading(true);
        const response = await fetch('/api/data');
        if (!response.ok) {
          throw new Error(`HTTP error! status: ${response.status}`);
        }
        const result = await response.json();
        setData(result);
      } catch (err) {
        setError(err.message);
        console.error('Fetch error:', err);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, []);

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error}</div>;
  if (!data) return <div>No data available</div>;

  return (
    <div>
      {data.items && data.items.map(item => (
        <p key={item.id}>{item.name}</p>
      ))}
    </div>
  );
}

Solution 1: Proper Build Configuration

Configure your build process correctly for deployment.

Package.json Configuration:

{
  "name": "my-react-app",
  "version": "1.0.0",
  "homepage": ".", // ✅ Use relative paths for GitHub Pages
  "private": true,
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-scripts": "5.0.1"
  },
  "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"
  },
  "devDependencies": {
    "gh-pages": "^4.0.0"
  }
}

Environment Configuration:

# .env.production
REACT_APP_API_URL=https://api.myapp.com
REACT_APP_ENV=production
GENERATE_SOURCEMAP=false

Public Folder Structure:

public/
├── index.html
├── favicon.ico
├── logo.png
├── manifest.json
└── robots.txt

Index.html Configuration:

<!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" />
    
    <!-- ✅ Use relative paths -->
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <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>
  </body>
</html>

Solution 2: Proper Asset Management

Handle assets correctly for production deployment.

// components/AssetManager.js
import React, { useState, useEffect } from 'react';
import logo from '../assets/logo.png'; // ✅ Import images directly

function AssetManager() {
  const [imageLoaded, setImageLoaded] = useState(false);
  const [imageError, setImageError] = useState(false);

  const handleImageLoad = () => {
    setImageLoaded(true);
  };

  const handleImageError = () => {
    setImageError(true);
    console.error('Failed to load image');
  };

  return (
    <div>
      {/* ✅ Handle image loading states */}
      {!imageLoaded && !imageError && <div>Loading image...</div>}
      {imageError && <div>Image failed to load</div>}
      
      <img
        src={logo}
        alt="Logo"
        onLoad={handleImageLoad}
        onError={handleImageError}
        style={{ display: imageLoaded ? 'block' : 'none' }}
      />
      
      {/* ✅ Use public URL for dynamic assets */}
      <img 
        src={`${process.env.PUBLIC_URL}/dynamic-image.jpg`} 
        alt="Dynamic" 
      />
    </div>
  );
}

// For CSS assets, import in component or index.js
// import '../styles/Component.css';

Solution 3: Error Boundaries and Fallbacks

Implement error boundaries to catch and handle errors gracefully.

// components/ErrorBoundary.js
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 service in production
    if (process.env.NODE_ENV === 'production') {
      console.error('Error caught by boundary:', error, errorInfo);
      // logErrorToService(error, errorInfo);
    }
  }

  render() {
    if (this.state.hasError) {
      return (
        <div className="error-boundary">
          <h2>Something went wrong.</h2>
          <details style={{ whiteSpace: 'pre-wrap' }}>
            {this.state.error && this.state.error.toString()}
            <br />
            {this.state.errorInfo.componentStack}
          </details>
          <button onClick={() => window.location.reload()}>
            Reload Page
          </button>
        </div>
      );
    }

    return this.props.children;
  }
}

// App.js with error boundary
import React from 'react';
import ErrorBoundary from './components/ErrorBoundary';
import MainContent from './components/MainContent';

function App() {
  return (
    <ErrorBoundary>
      <MainContent />
    </ErrorBoundary>
  );
}

export default App;

Solution 4: Proper API Configuration

Handle API calls correctly for different environments.

// utils/api.js
const API_BASE_URL = process.env.REACT_APP_API_URL || 'http://localhost:3001/api';

class ApiClient {
  constructor() {
    this.baseURL = API_BASE_URL;
  }

  async request(endpoint, options = {}) {
    const url = `${this.baseURL}${endpoint}`;
    
    const config = {
      headers: {
        'Content-Type': 'application/json',
        ...options.headers,
      },
      ...options,
    };

    try {
      const response = await fetch(url, config);
      
      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
      }
      
      return await response.json();
    } catch (error) {
      console.error('API request failed:', error);
      throw error;
    }
  }

  get(endpoint) {
    return this.request(endpoint, { method: 'GET' });
  }

  post(endpoint, data) {
    return this.request(endpoint, {
      method: 'POST',
      body: JSON.stringify(data),
    });
  }
}

export default new ApiClient();

// Component using API client
import React, { useState, useEffect } from 'react';
import api from '../utils/api';

function DataComponent() {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const result = await api.get('/data');
        setData(result);
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, []);

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error}</div>;

  return <div>{data && <pre>{JSON.stringify(data, null, 2)}</pre>}</div>;
}

Solution 5: Build Optimization and Debugging

Optimize your build and implement proper debugging.

// utils/build-debug.js
export const debugBuild = () => {
  if (process.env.NODE_ENV === 'production') {
    // ✅ Disable console logs in production
    console.log = () => {};
    console.error = () => {};
    console.warn = () => {};
  } else {
    // ✅ Enable detailed logging in development
    console.log('Development mode - detailed logging enabled');
  }
};

// utils/performance.js
export const measurePerformance = (name, fn) => {
  if (process.env.NODE_ENV === 'development') {
    const start = performance.now();
    const result = fn();
    const end = performance.now();
    console.log(`${name} took ${end - start} milliseconds`);
    return result;
  }
  return fn();
};

// App.js with build debugging
import React, { useEffect } from 'react';
import { debugBuild } from './utils/build-debug';

function App() {
  useEffect(() => {
    debugBuild();
  }, []);

  return <div>Your App Content</div>;
}

Solution 6: Deployment-Specific Configurations

Configure different settings for various deployment platforms.

For Netlify:

# netlify.toml
[build]
  command = "npm run build"
  publish = "build"
  environment = { NODE_VERSION = "18" }

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

[context.production.environment]
  REACT_APP_ENV = "production"
  GENERATE_SOURCEMAP = "false"

For Vercel:

// vercel.json
{
  "builds": [
    {
      "src": "package.json",
      "use": "@vercel/static-build",
      "config": {
        "distDir": "build"
      }
    }
  ],
  "routes": [
    {
      "src": "/(.*)",
      "dest": "/index.html"
    }
  ],
  "env": {
    "REACT_APP_API_URL": "https://api.myapp.com"
  }
}

For GitHub Pages:

# .github/workflows/deploy.yml
name: Deploy to GitHub Pages

on:
  push:
    branches: [main]

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v2
        with:
          node-version: '18'
      - run: npm ci
      - run: |
          npm run build
          echo "myapp.com" > build/CNAME
      - uses: peaceiris/actions-gh-pages@v3
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./build
          cname: myapp.com

Solution 7: Testing Production Builds

Test your production build locally before deployment.

// scripts/test-deploy.js
const { spawn } = require('child_process');
const path = require('path');

function testProductionBuild() {
  console.log('Building production version...');
  
  const buildProcess = spawn('npm', ['run', 'build'], {
    cwd: process.cwd(),
    stdio: 'inherit'
  });

  buildProcess.on('close', (code) => {
    if (code === 0) {
      console.log('Build successful! Testing locally...');
      
      // Serve the build locally
      const serveProcess = spawn('npx', ['serve', '-s', 'build'], {
        cwd: process.cwd(),
        stdio: 'inherit'
      });

      serveProcess.on('error', (error) => {
        console.error('Failed to serve build:', error.message);
      });

      console.log('Serving build at http://localhost:3000');
      console.log('Press Ctrl+C to stop');
    } else {
      console.error('Build failed!');
      process.exit(1);
    }
  });
}

// Run the test
testProductionBuild();

// Jest configuration for production testing
// jest.config.js
module.exports = {
  testEnvironment: 'jsdom',
  setupFilesAfterEnv: ['<rootDir>/src/setupTests.js'],
  moduleNameMapper: {
    '\\.(css|less|scss|sass)$': 'identity-obj-proxy',
    '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '<rootDir>/__mocks__/fileMock.js',
  },
  testMatch: [
    '**/__tests__/**/*.{js,jsx}',
    '**/?(*.)+(spec|test).{js,jsx}',
  ],
};

Solution 8: Console Error Monitoring

Implement error monitoring for production environments.

// utils/error-monitoring.js
class ErrorMonitor {
  constructor() {
    this.environment = process.env.NODE_ENV;
    this.appVersion = process.env.REACT_APP_VERSION || 'unknown';
  }

  logError(error, context = {}) {
    const errorData = {
      message: error.message,
      stack: error.stack,
      context,
      timestamp: new Date().toISOString(),
      userAgent: navigator.userAgent,
      url: window.location.href,
      environment: this.environment,
      version: this.appVersion,
    };

    if (this.environment === 'production') {
      // ✅ Send to error tracking service
      this.sendToErrorService(errorData);
    } else {
      // ✅ Log to console in development
      console.error('Error logged:', errorData);
    }
  }

  sendToErrorService(errorData) {
    // Example: Send to a logging service
    fetch('/api/errors', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(errorData),
    }).catch(err => {
      console.error('Failed to send error to service:', err);
    });
  }
}

export default new ErrorMonitor();

// Component using error monitoring
import React, { useEffect } from 'react';
import errorMonitor from '../utils/error-monitoring';

function MonitoredComponent() {
  useEffect(() => {
    const handleError = (error) => {
      errorMonitor.logError(error, { component: 'MonitoredComponent' });
    };

    window.addEventListener('error', (event) => {
      handleError(event.error);
    });

    return () => {
      window.removeEventListener('error', handleError);
    };
  }, []);

  return <div>Component with error monitoring</div>;
}

Solution 9: Performance and Bundle Analysis

Analyze your bundle to identify potential issues.

// webpack.config.js for analysis
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {
  // ... other config
  plugins: [
    // ... other plugins
    ...(process.env.ANALYZE_BUNDLE === 'true' ? [new BundleAnalyzerPlugin()] : []),
  ],
};

// package.json scripts for analysis
{
  "scripts": {
    "analyze": "ANALYZE_BUNDLE=true npm run build",
    "analyze:prod": "ANALYZE_BUNDLE=true npm run build && npx serve -s build"
  }
}

Performance Considerations

Optimized Production Build:

// Production-optimized patterns
function ProductionOptimizedComponent() {
  const [state, setState] = useState({
    data: [],
    loading: false,
    error: null
  });

  // ✅ Use functional updates to prevent race conditions
  const updateState = useCallback((updater) => {
    setState(prev => ({
      ...prev,
      ...updater(prev)
    }));
  }, []);

  // ✅ Memoize expensive operations
  const processedData = useMemo(() => {
    return state.data.map(item => ({
      ...item,
      processed: true
    }));
  }, [state.data]);

  return (
    <div>
      {state.loading && <div className="loading">Loading...</div>}
      {state.error && <div className="error">Error: {state.error}</div>}
      <ul>
        {processedData.map(item => (
          <li key={item.id}>{item.name}</li>
        ))}
      </ul>
    </div>
  );
}

Security Considerations

Secure Production Practices:

// Secure production practices
function SecureProductionComponent() {
  const [userInput, setUserInput] = useState('');

  const handleInputChange = (e) => {
    // ✅ Sanitize user input before processing
    const sanitizedInput = e.target.value
      .replace(/[<>]/g, '') // Basic XSS prevention
      .substring(0, 1000); // Limit input length
    
    setUserInput(sanitizedInput);
  };

  // ✅ Secure API calls with proper headers
  const secureApiCall = useCallback(async () => {
    try {
      const response = await fetch('/api/secure-endpoint', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-Requested-With': 'XMLHttpRequest',
        },
        body: JSON.stringify({ data: userInput }),
      });

      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
      }

      const result = await response.json();
      return result;
    } catch (error) {
      console.error('Secure API call failed:', error);
      throw error;
    }
  }, [userInput]);

  return (
    <div>
      <input 
        value={userInput}
        onChange={handleInputChange}
        placeholder="Enter secure input..."
      />
    </div>
  );
}

Common Mistakes to Avoid

1. Hardcoded Development URLs:

// ❌ Don't do this
function BadUrlComponent() {
  useEffect(() => {
    fetch('http://localhost:3001/api/data') // ❌ Hardcoded dev URL
      .then(response => response.json())
      .then(setData);
  }, []);
}

2. Missing Error Handling:

// ❌ Don't do this
function BadErrorHandling() {
  useEffect(() => {
    // ❌ No error handling - will crash in production
    fetch('/api/data').then(response => response.json()).then(setData);
  }, []);
}

3. Incorrect Public Path:

// ❌ Don't do this
function BadAssetComponent() {
  return (
    <img src="/absolute/path/logo.png" alt="Logo" /> // ❌ May break on subdirectories
  );
}

Alternative Solutions

Using React DevTools:

// Production-optimized component for DevTools
function ProductionOptimizedComponent() {
  const [data, setData] = useState(null);

  useEffect(() => {
    fetch('/api/data')
      .then(response => response.json())
      .then(setData)
      .catch(error => {
        console.error('Production error:', error);
        // Fallback to default data
        setData({ error: true });
      });
  }, []);

  return (
    <div data-testid="production-component">
      {data && <pre>{JSON.stringify(data, null, 2)}</pre>}
    </div>
  );
}

Feature Detection:

// Check for production features
function ProductionFeatureChecker() {
  const [isProduction, setIsProduction] = useState(false);

  useEffect(() => {
    setIsProduction(process.env.NODE_ENV === 'production');
  }, []);

  return (
    <div>
      {isProduction ? 'Production Mode' : 'Development Mode'}
    </div>
  );
}

Troubleshooting Checklist

When encountering a blank page after deployment:

  1. Check Browser Console: Look for JavaScript errors
  2. Verify Asset Loading: Ensure CSS and JS files are loading
  3. Test API Endpoints: Confirm API calls work in production
  4. Review Environment Variables: Verify all env vars are set
  5. Check Build Process: Ensure build completes without errors
  6. Validate Public Path: Confirm asset paths are correct
  7. Test Locally: Serve production build locally first

Conclusion

The React blank page after deploy error occurs due to various factors including asset loading issues, JavaScript errors, and configuration problems. By implementing proper build configurations, error handling, and deployment practices, you can ensure your React applications work seamlessly in production environments.

The key to resolving this issue is thorough testing of production builds, proper error handling, and ensuring all assets and API calls work correctly in the deployed environment. Whether you’re deploying to Netlify, Vercel, GitHub Pages, or custom servers, the solutions provided in this guide will help you create robust, production-ready React applications.

Remember to always test your builds locally, implement proper error boundaries, and use environment-appropriate configurations to ensure consistent behavior across all deployment environments.

Gautam Sharma

About Gautam Sharma

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

Related Articles

React

How to Fix React app works locally but not after build Error

Learn how to fix React apps that work locally but fail after build. Complete guide with solutions for production deployment and build optimization.

January 2, 2026
React

How to Fix Vite build works locally but fails in production Error

Learn how to fix Vite builds that work locally but fail in production. Complete guide with solutions for deployment and build optimization.

January 2, 2026
React

How to Fix React Router 404 Error on Page Refresh Error

Learn how to fix React Router 404 errors on page refresh. Complete guide with solutions for client-side routing and server configuration.

January 2, 2026