KHALID

Development
Jan 29, 2026
3 min read

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:3000

  • http://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

Related Articles