
How to Fix CORS Error in React/Node.js Projects (Complete Guide)
Introduction
If you’ve ever seen an error like:
pgsql
Access to fetch at 'http://api.example.com' from origin 'http://localhost:3000' has been blocked by CORS policy
…you’re not alone. This CORS error is one of the most common issues developers face when building full-stack applications using React (frontend) and Node.js (backend). In this blog post, we’ll break down what CORS is, why it happens, and how you can fix it step-by-step.
🔍 What is CORS?
CORS (Cross-Origin Resource Sharing) is a security mechanism implemented by browsers that restricts web applications from making requests to a different domain than the one the app was loaded from.
For example:
- Your React app runs on:
http://localhost:3000
- Your Node.js API runs on:
http://localhost:5000
Since they’re on different ports, the browser considers them different origins, and will block the request unless your server explicitly allows it.
⚠️ Common Scenarios Where CORS Error Occurs
- Frontend React app tries to fetch from a backend Node API on a different domain/port
- Fetch or Axios request fails with
blocked by CORS policy
- Using a 3rd-party API that doesn’t allow cross-origin requests
✅ Solution: Enable CORS on Your Node.js Server
🔧 Step 1: Install CORS Middleware
If you’re using Express.js, you can use the cors
package to enable CORS.
bash
npm install cors
🧠 Step 2: Use CORS in Your Express App
Option A: Allow All Origins (for development only)
js
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors()); // Enable CORS for all routes
app.get('/api', (req, res) => {
res.json({ message: 'Hello from server!' });
});
app.listen(5000, () => console.log('Server running on port 5000'));
🚨 Warning: Allowing all origins is fine for development, but not safe for production.
Option B: Allow Only Specific Origin
js
const corsOptions = {
origin: 'http://localhost:3000', // React app URL
credentials: true,
};
app.use(cors(corsOptions));
⚙️ Step 3: Handling Credentials (If Needed)
If you’re sending cookies or headers that require authentication:
js
const corsOptions = {
origin: 'http://localhost:3000',
credentials: true, // Important!
};
app.use(cors(corsOptions));
And in your React frontend, make sure to set:
js
fetch('http://localhost:5000/api', {
credentials: 'include',
});
Or with Axios:
js
axios.get('http://localhost:5000/api', { withCredentials: true });
🌐 Bonus: Proxying Requests in React (Dev Only)
If you want to bypass CORS entirely during development, you can use the proxy option in package.json
:
js
// In React's package.json
"proxy": "http://localhost:5000"
Now you can fetch from /api
instead of writing the full backend URL:
js
fetch('/api')
⚠️ This works only in development and with the React dev server.
🧪 Troubleshooting Tips
- ✅ Double-check if the Node server is running and reachable
- ✅ Ensure no firewall or VPN is blocking your ports
- ✅ Use browser dev tools → Network tab to inspect blocked requests
- ✅ Always restart the server after changing CORS settings
🔐 In Production: Be Secure!
In production, always:
- ✅ Allow only trusted origins
- ✅ Set secure CORS policies based on your use-case
- ✅ Avoid using
*
as origin if credentials or sensitive data is involved
📦 Sample Full Express CORS Setup
js
const express = require('express');
const cors = require('cors');
const app = express();
const corsOptions = {
origin: ['http://localhost:3000', 'https://yourdomain.com'],
credentials: true,
};
app.use(cors(corsOptions));
app.use(express.json());
app.get('/api/data', (req, res) => {
res.json({ message: 'CORS is working!' });
});
app.listen(5000, () => {
console.log('Server is running on port 5000');
});
🏁 Final Thoughts
CORS errors can seem frustrating at first, but once you understand how browser security and headers work, the solution becomes straightforward. The key is to make sure your Node.js backend allows requests from your React frontend, either temporarily (for dev) or securely (for prod).
By following the steps above, you’ll have a CORS-free setup that works smoothly!