🚀 Client-Side vs Server-Side CORS: Understanding the Real Difference

Published: (December 4, 2025 at 03:49 PM EST)
3 min read
Source: Dev.to

Source: Dev.to

Cover image for 🚀 Client-Side vs Server-Side CORS: Understanding the Real Difference

If you’ve ever screamed at your monitor because of a mysterious CORS error…
Congratulations — you are officially a web developer. 🎉

CORS is like that strict bouncer outside the club who won’t let you in even though you swear you’re on the list.

What Is CORS, Really?

CORS stands for Cross‑Origin Resource Sharing — which sounds fancy, but really means:

“Hey browser, can this website talk to that other website? Or is it a stranger‑danger situation?”

The browser is extremely paranoid.
If domain A calls domain B, the browser goes:

“Hold up. Who sent you? Show me your passport, Aadhar card, PAN card, and two 2×2 photos.”

Client‑Side vs Server‑Side CORS: The Plot Twist

People keep saying “client‑side CORS” and “server‑side CORS,” but the truth is:

Only the server decides CORS. The client is just a confused teenager asking for permission.

Both sides play a role — so let’s decode them.

Client‑Side CORS (AKA: The Illusion of Control)

Developers often write:

fetch("/api", { mode: "cors" })

and expect the browser to say:

“Yes sir! CORS enabled! You’re a genius!”

But the browser actually enforces the rules:

  • mode: "cors" → “Please let me in!”
  • mode: "no-cors" → “Fine, I’ll leave. I didn’t want to see the response anyway.”
  • credentials: "include" → “Here are my cookies, please don’t judge.”

⚠️ The client cannot enable CORS. It can only request it; the server still holds the key.

Server‑Side CORS (The Real Boss Here)

This is where the actual magic happens. If the server doesn’t approve your origin, the browser blocks the request.

Typical response headers:

Access-Control-Allow-Origin: https://myapp.com
Access-Control-Allow-Methods: GET, POST, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Allow-Credentials: true

Only after receiving the proper headers does the browser allow the request.

Example (Express.js)

const cors = require('cors');

app.use(cors({
  origin: "https://myapp.com",
  credentials: true
}));

Example (Next.js API Route)

export default function handler(req, res) {
  res.setHeader("Access-Control-Allow-Origin", "https://myapp.com");
  res.setHeader("Access-Control-Allow-Credentials", "true");
  // ...handle request
}

If you forget even one header, you’ll get a CORS error.

Simple vs Preflight Requests (AKA: Browser Drama)

Simple requests

These are “chill.” The browser allows:

  • GET or POST with simple headers (e.g., Accept, Content-Type limited to text/plain, multipart/form-data, application/x-www-form-urlencoded).

Preflight requests

These happen when you use:

  • Methods like PUT, PATCH, DELETE
  • Custom headers
  • A JSON body (i.e., Content-Type: application/json)

The browser sends an OPTIONS request first, asking the server for permission. If the server doesn’t respond correctly, the actual request is blocked.

Summary Table for Geniuses Who Scrolled Too Fast

ThingClient SideServer Side
Who’s in control?Lol. Not you.The real boss.
Can it allow a request?❌ Nope✅ Absolutely
Can it trigger preflight?✅ Yes⚠️ Must respond properly
Is it real CORS?❌ No✅ Yes, 100 % legit

Final Thoughts

CORS errors might feel like a personal attack from the universe, but the rule is simple:

  1. Client makes a request.
  2. Server decides whether to allow it (by sending the appropriate headers).
  3. Browser enforces the decision.

When each part does its job, CORS is painless. When something goes wrong… enjoy the next few hours of debugging. 😅

Back to Blog

Related posts

Read more »