DEV Community

Cover image for How to Fix CORS Errors in React: The Practical Guide (With Real Solutions)
Blogs World
Blogs World

Posted on

How to Fix CORS Errors in React: The Practical Guide (With Real Solutions)

The Error Everyone Hits

You're building a React app. API works in Postman. Works in curl. Works everywhere.

Then you put it in your React component:

useEffect(() => {
  fetch('https://api.example.com/data')
    .then(res => res.json())
    .then(data => console.log(data))
    .catch(err => console.log(err))
}, [])
Enter fullscreen mode Exit fullscreen mode

Browser console:

Access to XMLHttpRequest at 'https://api.example.com/data' 
from origin 'http://localhost:3000' has been blocked by CORS policy: 
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Enter fullscreen mode Exit fullscreen mode

Why? Browser security. Not your fault. But also... frustrating.

Here's what actually works:


Solution 1: Backend Fix (The Right Way)

The correct fix is on the backend, not frontend.

Your backend needs to send:

Access-Control-Allow-Origin: http://localhost:3000
Enter fullscreen mode Exit fullscreen mode

If you control the backend:

Node.js/Express:

const cors = require('cors');

app.use(cors({
  origin: 'http://localhost:3000', // Your frontend URL
  credentials: true
}));

app.get('/api/data', (req, res) => {
  res.json({ message: 'success' });
});
Enter fullscreen mode Exit fullscreen mode

Laravel/PHP:

header('Access-Control-Allow-Origin: http://localhost:3000');
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE');
header('Access-Control-Allow-Credentials: true');
header('Content-Type: application/json');
Enter fullscreen mode Exit fullscreen mode

Python/Flask:

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
CORS(app, origins=['http://localhost:3000'])

@app.route('/api/data')
def data():
    return {'message': 'success'}
Enter fullscreen mode Exit fullscreen mode

That's it. Your React code now works.


Solution 2: Proxy During Development

If you DON'T control the backend, or you're developing locally:

Create a proxy in package.json:

{
  "proxy": "https://api.example.com"
}
Enter fullscreen mode Exit fullscreen mode

Then in React, remove the domain:

// ❌ Before (gets CORS error)
fetch('https://api.example.com/data')

// ✅ After (goes through proxy)
fetch('/data')
Enter fullscreen mode Exit fullscreen mode

Why this works: React's dev server acts as a middleman. Browsers don't block same-origin requests.

⚠️ Important: This only works in development (npm start). Production builds need the backend fix.


Solution 3: CORS Proxy (Temporary, Not Recommended)

If you're stuck and can't change the backend:

const corsProxy = 'https://cors-anywhere.herokuapp.com/';
const apiUrl = 'https://api.example.com/data';

fetch(corsProxy + apiUrl)
  .then(res => res.json())
  .then(data => console.log(data))
Enter fullscreen mode Exit fullscreen mode

Why this sucks:

  • Extra latency (request goes through a third server)
  • Free CORS proxies get rate-limited
  • Security risk (your data goes through someone else's server)
  • Will break in production

Use this only for testing. Don't ship it.


Solution 4: Credentials & Cookies

If your API requires authentication (cookies, JWT):

// ❌ Doesn't send cookies
fetch('https://api.example.com/data')

// ✅ Sends cookies
fetch('https://api.example.com/data', {
  credentials: 'include'
})
Enter fullscreen mode Exit fullscreen mode

Backend also needs to allow credentials:

Express:

cors({
  origin: 'http://localhost:3000',
  credentials: true  // ← This line
})
Enter fullscreen mode Exit fullscreen mode

The Checklist (Before Asking for Help)

  1. ✅ Does your backend have CORS headers set?

    • Check: curl -I https://api.example.com/data | grep Access-Control
    • If nothing appears → backend needs fixing
  2. ✅ Is it a preflight request being blocked?

    • Look for OPTIONS request in Network tab
    • If it fails → backend doesn't handle preflight
  3. ✅ Are you sending credentials?

    • If yes → both frontend needs credentials: 'include' AND backend needs credentials: true
  4. ✅ Is this production or development?

    • Dev: use proxy
    • Production: backend must have CORS headers

Real Example: Fetch with All Options

Here's a complete, production-ready example:

async function fetchUserData(userId) {
  try {
    const response = await fetch(`https://api.example.com/users/${userId}`, {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${token}`
      },
      credentials: 'include'  // Include cookies if backend requires auth
    });

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

    const data = await response.json();
    return data;
  } catch (error) {
    console.error('CORS or network error:', error);
  }
}
Enter fullscreen mode Exit fullscreen mode

What I've Learned (After Fixing This 100+ Times)

  1. 99% of CORS errors are a backend configuration issue, not a React problem
  2. The proxy solution feels like magic locally, but it's a trap for production — always fix the backend
  3. Credentials require matching configurations on both sides — one side correct isn't enough
  4. Preflight requests (OPTIONS) are the actual blocker — if those fail, everything fails

The Fastest Debug Path

  1. Open DevTools → Network tab
  2. Try your API call
  3. Look for the failed request
  4. Click it → Response headers → search for Access-Control-Allow-Origin
  5. If it's missing → backend problem
  6. If it's there but says a different origin → update backend to allow your URL

Still Stuck?

Drop the actual error message in the comments. Knowing:

  • What frontend (React, Vue, etc.) you're using
  • What backend (Express, Laravel, etc.) you're using
  • Whether this is local dev or production

...helps me (and others) give you the exact fix.

Cheers ☕


Want more React debugging tips? I write practical solutions to the problems that actually kill deployments. Check out my full blog for deep dives on error handling, performance, and production gotchas.


Author: Ankit Khoiwal | Full-stack developer | Every post is from real production experience

Top comments (0)