Understanding CORS in a MERN Stack Application: A Problem I Faced and Solved
While working on a full-stack project using the MERN stack (MongoDB, Express, React, Node.js), I ran into an issue that many developers encounter at some point: CORS errors.
At the time, I didn't even know what CORS was. I was simply trying to connect my React frontend with my Express backend, but the browser kept blocking my requests.
This article explains the issue I faced, how I fixed it initially, and the better approaches I later learned.
The Problem I Faced
My project had two separate parts running locally:
- Frontend (React):
http://localhost:3000 - Backend (Express API):
http://localhost:5000
When my React app tried to fetch data from the backend, I wrote something like this:
fetch("http://localhost:5000/api/data")
Instead of getting the response, I saw this error in the browser console:
Access to fetch at 'http://localhost:5000/api/data'
from origin 'http://localhost:3000'
has been blocked by CORS policy
At that moment, I didn't understand why this was happening.
What CORS Actually Is
CORS stands for Cross-Origin Resource Sharing.
Browsers treat requests as cross-origin if any of the following differ:
- domain
- port
- protocol
Example:
| Frontend | Backend | Result |
|---|---|---|
| localhost:3000 | localhost:5000 | Cross-Origin |
| example.com | api.example.com | Cross-Origin |
| http vs https | Different origin | Cross-Origin |
Browsers block these requests by default for security reasons. This prevents malicious websites from sending unauthorized requests to other servers on behalf of users.
My First Fix (Allowing All Origins)
At the time, I just wanted the application to work. After searching online, I discovered the cors middleware for Express.
First, I installed it:
npm install cors
Then I added this to my server:
import cors from "cors";
app.use(cors({
origin: "*"
}));
This allowed all origins to access the API. After doing this, my React application could finally communicate with the backend. Problem solved — at least temporarily.
The Problem With origin: "*"
Later, I learned that using origin: "*" means any website can access your API.
For simple public APIs this may be acceptable, but for most applications it is not recommended. If your API handles user accounts, authentication, or private data, then allowing every origin could introduce security risks.
The Better Solution
A more secure approach is to allow only the frontend domain.
Example:
app.use(cors({
origin: "http://localhost:3000"
}));
Now the server only accepts requests from the React application. This is a much safer configuration.
Other Ways to Fix CORS
During my research, I discovered there are multiple ways to handle CORS depending on the project.
1. Allow Multiple Origins
If your app has multiple frontends, you can allow several origins.
const allowedOrigins = [
"http://localhost:3000",
"https://mywebsite.com"
];
app.use(cors({
origin: allowedOrigins
}));
2. Manual CORS Headers
You can also set headers manually in Express.
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "http://localhost:3000");
res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
res.header("Access-Control-Allow-Headers", "Content-Type");
next();
});
However, using the cors middleware is usually easier and cleaner.
3. Proxy Setup (Frontend Development)
Another approach during development is to use a proxy configuration in React.
Example in package.json:
"proxy": "http://localhost:5000"
This allows the frontend to forward API requests through the development server, avoiding CORS issues locally.
What I Learned From This Experience
- Browser security rules are strict and intentional
- CORS is not a server error — it's a browser protection
- Quick fixes like
origin: "*"work but may not be secure - Understanding the root cause is better than copying solutions
Final Thoughts
CORS errors are extremely common in modern web development, especially when working with separated frontend and backend applications.
At first, the error messages can be confusing, but once you understand that CORS is simply a browser security policy, solving the issue becomes straightforward.
Today, whenever I set up a new MERN stack project, configuring CORS properly is one of the first things I do.