React Works in Development but Fails After Production Build – Complete Debugging Guide | FreeLearning365.com

React Works in Development but Fails After Production Build – Complete Debugging Guide | FreeLearning365.com
FreeLearning365.com 🐛 Production Debug
🚨 Production-Only Bugs

React Works in Development
but Fails After Production Build

“It works on my machine!” — The classic developer lament. Your React app runs perfectly in npm start but breaks in production. This guide provides a complete debugging framework to identify and fix production-only issues, with real solutions for every common cause.

🔍 1. Introduction

You've just deployed your React app to production, and everything seems fine — until a user reports a crash, or you see a blank white page. You test locally with npm start and it works flawlessly. This is the production-only bug — one of the most frustrating experiences in frontend development.

The differences between development and production are many: minified code, different environment variables, optimized builds, and different server configurations. This guide will walk you through the systematic process of identifying and fixing these elusive issues, covering everything from environment variables to service worker caching.

💡 Quick fact: The most common cause of production-only failures is using process.env variables that are not available in production, or relying on development-only features like hot reloading.

2. Common Causes

Before diving into specific fixes, let's outline the usual suspects. Here's what changes between development and production builds:

  • Environment variables: NODE_ENV=development vs production, and custom variables like REACT_APP_* may be missing.
  • Code minification: Variable names are shortened, which can break code that relies on function.name or instanceof checks.
  • Dead code elimination: Tree-shaking removes unused code, which might be needed for side effects or polyfills.
  • Server configuration: Production servers (Nginx, Apache, Vercel) may not handle client-side routing correctly.
  • CORS policies: Production API endpoints often have stricter CORS rules.
  • Service workers: Caching can cause stale assets to be served.
  • Polyfills: Development servers often include polyfills automatically, but production builds may not.
  • Lazy loading & code splitting: Dynamic imports might fail if paths are incorrect in production.
⚠️ Important: Always test your production build locally before deploying. Use npm run build and serve it with a static server like serve -s build.

🔐 3. Environment Variables

In development, you often have a .env.development file with API endpoints and keys. In production, you need a .env.production file or inject variables differently.

📌 How React Handles Environment Variables

With Create React App (CRA), only variables prefixed with REACT_APP_ are embedded in the build. In Vite, you use VITE_ prefix. These variables are replaced at build time, not at runtime.

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

Then in your code:

const apiUrl = process.env.REACT_APP_API_URL; fetch(`${apiUrl}/users`);

🔧 What to Check

  • Ensure .env.production exists and has the correct values.
  • Check that you're not using process.env.NODE_ENV for logic that affects production.
  • For server-side rendered apps (Next.js), use NEXT_PUBLIC_* variables.
  • Avoid using process.env directly in frontend code without the prefix.
✅ Pro tip: Use a library like dotenv for Node.js backends, and always commit .env.example but not the real .env files.

✂️ 4. Minification & Dead Code

Production builds minify your code, rename variables, and remove code considered "unused." This can break things if you rely on:

  • Function.prototype.name for component identification.
  • instanceof checks with custom classes.
  • Side effects that are removed by tree-shaking.

🔧 How to Fix

  • Avoid using function.name for logic — use a static property or displayName.
  • Use typeof or constructor.name carefully.
  • Mark files with side effects in package.json ("sideEffects": false may cause issues).
  • In CRA, you can customize the build with react-app-rewired or craco to change minification settings.

To debug, you can build with source maps enabled to see the original code.

# Build with source maps GENERATE_SOURCEMAP=true npm run build

🧭 5. Routing & Server Configuration

React apps often use client-side routing (React Router). In development, the dev server handles all routes. In production, your web server must be configured to serve index.html for all routes, otherwise you get a 404 when refreshing a sub-route.

📌 Server Configuration Examples

Nginx:

location / { try_files $uri $uri/ /index.html; }

Apache: Use a .htaccess file:

<IfModule mod_rewrite.c> RewriteEngine On RewriteBase / RewriteRule ^index\.html$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.html [L] </IfModule>

Vercel/Netlify: Use a _redirects file or vercel.json.

# _redirects /* /index.html 200

🔧 Check basename

If your app is deployed to a subdirectory, set the basename in React Router:

<BrowserRouter basename="/myapp"> <App /> </BrowserRouter>
💡 Pro tip: Use %PUBLIC_URL% in your index.html to ensure asset paths are correct.

🌐 6. CORS & API Issues

In development, you might use a proxy to avoid CORS. In production, the proxy is not present, so your API requests go directly to the API server. This can trigger CORS errors if the server isn't configured correctly.

🔧 Fixes

  • Ensure your API server includes CORS headers (Access-Control-Allow-Origin) with your production domain.
  • If you control the API, add your production domain to the allowed origins.
  • Alternatively, use a backend proxy (like a Node.js server) to forward requests, avoiding CORS entirely.
  • In Next.js, use API routes to proxy requests.
⚠️ Note: CORS errors in production often appear as "Failed to fetch" or network errors. Check the browser's Network tab to confirm.

📦 7. Service Worker & Caching

If you're using a service worker (e.g., CRA's Workbox), it might cache old assets, causing a mismatch between the JavaScript bundle and the HTML. This can lead to errors that don't appear in development.

🔧 How to Fix

  • Clear the service worker cache: In DevTools, go to Application → Service Workers and unregister.
  • Ensure your service worker updates correctly by implementing versioning.
  • In CRA, you can customize the service worker with craco or ejecting.
  • For a quick fix, you can disable the service worker in production (but this removes offline capabilities).

Also check browser caching: Sometimes the index.html is cached, causing old assets to load. Use cache-control headers correctly.

🐞 8. Debugging Techniques

Here's how to systematically debug production-only issues.

📌 Step 1: Replicate Production Locally

Build your app and serve it with a static server:

npm run build npx serve -s build -l 5000

Visit http://localhost:5000 and test. If the error doesn't appear here, the issue is with your hosting environment.

📌 Step 2: Enable Source Maps

Build with source maps to get readable stack traces.

GENERATE_SOURCEMAP=true npm run build

Then open the browser console and inspect the error.

📌 Step 3: Use Error Boundaries

Wrap your app with an error boundary to catch errors and display a fallback UI.

class ErrorBoundary extends React.Component { componentDidCatch(error, info) { console.error('Caught error:', error, info); // Send to logging service } render() { if (this.state.hasError) { return <h1>Something went wrong.</h1>; } return this.props.children; } }

📌 Step 4: Use Console Logs in Production

You can keep some console.log statements in production (be careful not to leak sensitive info). They can help trace the flow.

📌 Step 5: Leverage Logging Services

Tools like Sentry, LogRocket, or Datadog can capture production errors and provide context.

📌 Step 6: Analyze Bundle

Use source-map-explorer to visualize bundle composition.

npx source-map-explorer 'build/static/js/*.js'

This helps find duplicate dependencies or unexpected large files.

❓ Frequently Asked Questions

🏆 10. Best Practices

  • Test production build locally: Always run npm run build and serve it locally before deploying.
  • Use environment variables correctly: Separate development and production configurations.
  • Implement error boundaries: Catch runtime errors gracefully.
  • Use logging services: Integrate Sentry or similar to monitor production errors.
  • Set up CI/CD pipelines: Automatically build and test your app before deployment.
  • Optimize bundle: Use code splitting and lazy loading to reduce bundle size.
  • Configure server for SPA routing: Ensure index.html is served for all routes.
  • Manage caching: Use proper Cache-Control headers and versioned asset filenames.
  • Test on multiple browsers: Production errors can be browser-specific.
  • Keep dependencies updated: Outdated packages can cause production issues.
✅ Final thought: Production-only bugs are manageable with a systematic approach. By understanding the differences between dev and prod, and using the right debugging tools, you can quickly identify and fix these issues, ensuring a smooth experience for your users.

Post a Comment

0 Comments