How to Handle CORS in Node.js When Your Frontend URL is Dynamic (Unlimited Subdomains)
If your frontend URLs are unlimited but share the same main domain (like *.vercel.app), you don’t need to whitelist every subdomain manually. Instead, use a dynamic CORS origin check that allows any hostname ending with .vercel.app and blocks all other domains. This keeps your backend secure while supporting infinite frontend deployments.
✅ Your frontend URL is dynamic, meaning you don’t know the subdomain in advance.
For example, your frontend can be deployed to:
https://khalid.vercel.app
https://hasan.vercel.app
https://anything.vercel.app
And the number of frontends can be infinite.
So the question becomes:
How do you set CORS in Node.js if you don’t know the exact frontend domain?
Let’s solve it properly, securely, and professionally ✅
✅ What is CORS?
CORS stands for Cross-Origin Resource Sharing.
When your frontend is hosted at:
https://khalid.vercel.app
and your backend is hosted at:
https://api.mybackend.com
the browser blocks requests by default unless your backend explicitly allows the frontend using CORS.
That’s why you get errors like:
CORS policy: No 'Access-Control-Allow-Origin' header...Blocked by CORS...
✅ The Wrong Solution (Don’t Do This)
Many developers quickly do this:
app.use(cors({ origin: "*" }));This is dangerous because it allows:
✅ any website
✅ any domain
✅ anyone to call your API
If your backend has authentication, user data, or payments — this is risky.
✅ The Correct Solution: Allow Only Trusted Domains Dynamically
In our case, we trust any subdomain of vercel.app, like:
✅ *.vercel.app
But we should block random websites like:
❌ https://evil.com
So we need a dynamic CORS validator.
✅ Step 1: Install CORS Package
If you’re using Express:
npm install cors✅ Step 2: Add Dynamic CORS in Express
Here’s a clean and secure setup:
const cors = require("cors");
const allowedMainDomains = [
"vercel.app",
"yourdomain.com", // you can add your custom domains too
];
function isAllowedOrigin(origin) {
if (!origin) return true; // allow Postman / server-to-server calls
try {
const url = new URL(origin);
const hostname = url.hostname; // e.g. khalid.vercel.app
return allowedMainDomains.some(
(domain) => hostname === domain || hostname.endsWith("." + domain)
);
} catch (err) {
return false;
}
}
app.use(
cors({
origin: function (origin, callback) {
if (isAllowedOrigin(origin)) {
callback(null, true);
} else {
callback(new Error("Not allowed by CORS"));
}
},
credentials: true, // if you're using cookies/session auth
})
);
✅ How This Works
Let’s test the logic:
✅ Allowed
khalid.vercel.app✅hasan.vercel.app✅random123.vercel.app✅
❌ Blocked
evil.com❌vercel.app.evil.com❌ (this looks similar but it’s NOT a real subdomain)
✅ Important Note: Cookies & Credentials
If your frontend uses cookies or session auth, your fetch request must include credentials:
fetch("https://api.mybackend.com/data", {
method: "GET",
credentials: "include",
});And your backend should keep:
credentials: true⚠️ Remember: If credentials: true, your CORS origin cannot be *.
✅ Bonus: Allow Localhost for Development
Most teams also need to allow frontend development locally:
http://localhost:3000http://localhost:5173
You can update the function:
function isAllowedOrigin(origin) {
if (!origin) return true;
try {
const { hostname } = new URL(origin);
if (hostname === "localhost") return true;
return allowedMainDomains.some(
(domain) => hostname === domain || hostname.endsWith("." + domain)
);
} catch {
return false;
}
}
Now your backend supports both:
✅ production frontend subdomains
✅ localhost dev environments
Category
Development