Real-world examples of CORS in Node.js API: 3 practical setups that actually work

If you build APIs for the web, you’ve fought with CORS at some point. Instead of another dry theory piece, this guide walks through real-world examples of CORS in a Node.js API: 3 practical examples you can drop into your code today. We’ll look at the **simple open API**, the **locked-down production API**, and a **per-route CORS strategy** that fits modern microservice and SPA architectures. You’ll see how these examples of CORS behave with browsers, how preflight requests work, and how to avoid the classic “CORS error” that clogs up every front-end dev’s console. Along the way, we’ll add a few more scenarios—like handling cookies, API gateways, and local development setups—so you can adapt these patterns to your own stack. If you want CORS in your Node.js API to stop feeling like guesswork and start acting predictable, these practical examples will get you there.
Written by
Jamie
Published

Most CORS explainers start with dry definitions. Let’s skip that and jump straight into examples of CORS in a Node.js API that you’d actually run in 2024–2025.

We’ll build around a simple Express server, then layer in different CORS configurations:

npm init -y
npm install express cors
// server.js
const express = require('express');
const cors = require('cors');

const app = express();
app.use(express.json());

app.get('/public', (req, res) => {
  res.json({ message: 'Public data' });
});

app.listen(4000, () => {
  console.log('API running on http://localhost:4000');
});

Now let’s walk through three practical examples of CORS in a Node.js API, plus a few extra scenarios you’ll hit in real projects.


Example 1: Wide-open CORS for public APIs and local development

This is the “just make it work” setup. You’ll see it in tutorials, internal tools, and dev environments. It allows any origin and most basic methods.

// Example 1: Allow all origins (development or public demo)
const cors = require('cors');

app.use(cors());

// Optional: be explicit
// app.use(cors({ origin: '*', methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'] }));

In this first example of CORS in a Node.js API, the cors() middleware with no options tells browsers:

  • Any website can call this API.
  • Simple requests (GET, basic POST) just work.
  • Preflight requests (OPTIONS) get an automatic OK.

When this “open” CORS example makes sense

Real examples where this pattern is fine:

  • A public, read-only API with no user data (e.g., a demo weather or crypto price feed).
  • Internal dashboards behind VPN or SSO where network controls are already strict.
  • Local development where your React/Vue front end runs on http://localhost:3000 and your Node.js API runs on http://localhost:4000.

From an SEO perspective, many developers search for “best examples of CORS in Node.js API: 3 practical examples” and land here first. But in production, this wide-open pattern is rarely what you want.

Hidden gotcha: cookies and Authorization headers won’t work

If you later try to send cookies or Authorization: Bearer ... headers from the browser, this open example suddenly stops working for authenticated flows. You’ll need a more specific configuration, which brings us to the second pattern.


Example 2: Locked-down CORS for a single front-end origin

Most real apps in 2024–2025 have a single primary front end hitting a single API: think React SPA + Node.js backend. In that case, the best examples of CORS configurations are the ones that:

  • Allow only a known origin (your front-end URL).
  • Allow credentials (cookies, Authorization headers).
  • Restrict methods and headers to what you actually use.

Here’s a tighter, production-style example of CORS in a Node.js API:

const cors = require('cors');

const allowedOrigin = process.env.FRONTEND_ORIGIN || 'https://app.example.com';

app.use(cors({
  origin: allowedOrigin,
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization'],
  credentials: true,
}));

// Browsers send OPTIONS preflight for some requests
app.options('*', cors({
  origin: allowedOrigin,
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization'],
  credentials: true,
}));

This is one of the most common real examples of CORS in Node.js API setups in production apps.

Why this pattern actually works in 2024–2025

Modern SPAs often rely on:

  • JWT in Authorization headers for auth.
  • SameSite=None; Secure cookies for session-based auth.
  • Custom headers like X-Request-Id or X-Client-Version.

Browsers treat those as non-simple requests, so they send a preflight OPTIONS request. If your CORS config doesn’t match the actual method and headers, the browser quietly blocks the call.

By explicitly listing allowedHeaders and methods, this example keeps your CORS behavior predictable and easier to debug.

Common mistakes with this CORS example

Even experienced teams trip over a few recurring issues:

  • Setting origin: '*' while also using credentials: true – browsers will reject this.
  • Forgetting to handle OPTIONS requests, which makes preflight fail.
  • Allowing Authorization but forgetting a custom header like X-Requested-With, causing random failures.

For a deeper look at CORS behavior from the browser’s perspective, the MDN docs are still the gold standard: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS


Example 3: Per-route CORS for multi-tenant and microservice setups

Sometimes your API isn’t just one thing. Maybe you have:

  • A public /public endpoint for marketing pages.
  • A locked-down /api for your main web app.
  • A partner-only /partner route for B2B integrations.

In that case, global CORS middleware is too blunt. You want route-level CORS rules. Here’s a more advanced example of CORS in a Node.js API using per-route configuration:

const cors = require('cors');

const publicCors = cors({ origin: '*' });

const appCors = cors({
  origin: 'https://app.example.com',
  methods: ['GET', 'POST'],
  credentials: true,
});

const partnerCors = cors({
  origin: [/\.partner1\.com\(/, /\.partner2\.com\)/],
  methods: ['GET', 'POST', 'PUT'],
  allowedHeaders: ['Content-Type', 'Authorization', 'X-Partner-Key'],
});

// Public route: any origin can read
app.get('/public', publicCors, (req, res) => {
  res.json({ message: 'Public data' });
});

// Main app API: only your SPA
app.get('/api/profile', appCors, (req, res) => {
  res.json({ user: 'Jane Doe' });
});

// Partner API: only specific partner subdomains
app.post('/partner/orders', partnerCors, (req, res) => {
  res.status(201).json({ status: 'created' });
});

This is one of the best examples of CORS in Node.js API design when you have multiple clients with different trust levels. It mirrors how many SaaS platforms structure their APIs today.


Extra real-world scenarios: 4 more examples of CORS patterns you’ll actually use

The title promised 3 practical setups, but real life is messier than that. Here are four additional real examples of CORS in Node.js API configurations that show up in modern stacks.

Example 4: Dynamic CORS origin checking at runtime

Sometimes you can’t hard-code all allowed origins. Think multi-tenant SaaS where each customer gets a custom domain.

const cors = require('cors');

const allowedOrigins = new Set([
  'https://app.example.com',
  'https://admin.example.com',
]);

const corsOptionsDelegate = (req, callback) => {
  const origin = req.header('Origin');
  let corsOptions;

  if (origin && allowedOrigins.has(origin)) {
    corsOptions = { origin: true, credentials: true };
  } else {
    corsOptions = { origin: false };
  }

  callback(null, corsOptions);
};

app.use(cors(corsOptionsDelegate));

This example of dynamic CORS in a Node.js API lets you:

  • Read allowed origins from a database or config service.
  • Toggle access without redeploying the API.
  • Log or alert when unknown origins attempt access.

Example 5: CORS with cookies for legacy session-based auth

Not every app has moved to pure JWT. If you’re using session cookies, your CORS config needs to match modern browser rules (especially Chrome’s SameSite changes).

const cors = require('cors');
const session = require('express-session');

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

app.use(session({
  secret: process.env.SESSION_SECRET,
  resave: false,
  saveUninitialized: false,
  cookie: {
    httpOnly: true,
    secure: true,
    sameSite: 'none',
  },
}));

This is a very common example of CORS in Node.js API setups for organizations modernizing older apps: front end is new, backend still uses sessions.

If you’re handling authentication and sensitive data, it’s worth reviewing federal guidance on secure web sessions, such as NIST’s recommendations around cookies and session management: https://csrc.nist.gov

Example 6: CORS behind an API gateway or reverse proxy

In larger deployments, CORS might be handled partly by NGINX, an API gateway, or a cloud load balancer. Your Node.js API still needs to play nicely.

A realistic pattern in 2024–2025:

  • Gateway adds Access-Control-Allow-Origin for public endpoints.
  • Node.js adds CORS headers only for internal or special routes.
// Only add CORS for internal tools; public CORS handled by gateway
app.use('/internal', cors({
  origin: 'https://internal-tools.example.com',
  methods: ['GET', 'POST'],
}));

If you’re in a regulated industry (healthcare, finance, government), you’ll often see CORS policies documented alongside security controls. For example, U.S. government web security guidance emphasizes origin and header restrictions as part of a defense-in-depth model: https://www.cisa.gov

Example 7: CORS in local dev with multiple front ends

Modern teams often run multiple local front ends: admin UI, main app, documentation site. Here’s a simple but realistic example:

const cors = require('cors');

const devOrigins = [
  'http://localhost:3000', // main app
  'http://localhost:3001', // admin
  'http://localhost:3002', // docs
];

app.use(cors({
  origin: devOrigins,
  credentials: true,
}));

This kind of configuration is one of the best examples of CORS in Node.js API setups that keep development flexible without accidentally allowing the whole internet.


Debugging CORS: why your “perfect” example still fails

Even with good examples of CORS in a Node.js API, things go wrong. A few practical debugging habits:

  • Check the browser’s network tab: look at the OPTIONS preflight response.
  • Verify headers: your API must send Access-Control-Allow-Origin, Access-Control-Allow-Methods, and Access-Control-Allow-Headers that match what the browser asked for.
  • Log the Origin header: during development, log req.headers.origin to see who’s calling you.

If you’re working in health or medical contexts where cross-origin data access raises privacy questions, organizations like the U.S. National Institutes of Health publish guidance on protecting personal health information in web apps: https://www.nih.gov


FAQ: common questions about CORS in Node.js APIs

What are some real examples of CORS configurations in Node.js?

Real examples of CORS in Node.js API setups include:

  • Allow-all for public or demo APIs.
  • Single-origin with credentials for SPAs.
  • Per-route CORS for public vs. private endpoints.
  • Dynamic origin checking for multi-tenant apps.
  • Cookie-based session APIs with SameSite=None and credentials: true.

All of these examples of CORS patterns appear in production systems today.

Can you show an example of allowing only GET and POST with CORS?

Yes. Here’s a compact example of CORS in a Node.js API that only allows GET and POST from a specific origin:

app.use(cors({
  origin: 'https://app.example.com',
  methods: ['GET', 'POST'],
}));

Browsers will block PUT, PATCH, or DELETE requests from other origins in this setup.

Do I always need the cors package for Node.js?

No. You can manually set CORS headers with plain Express:

app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', 'https://app.example.com');
  res.header('Access-Control-Allow-Methods', 'GET,POST');
  res.header('Access-Control-Allow-Headers', 'Content-Type,Authorization');
  if (req.method === 'OPTIONS') {
    return res.sendStatus(204);
  }
  next();
});

But for most developers, the cors middleware is easier to reason about and less error-prone.

How do I test these examples of CORS in Node.js API locally?

Run your Node.js API on one port (say 4000) and a simple front end (even a static HTML file served by live-server or Vite) on another port (3000). Open the browser console, make fetch calls, and watch for CORS errors. Adjust the origin and methods in your examples of CORS config until the browser stops complaining.


If you remember nothing else, remember this: the best examples of CORS in Node.js API design are the ones that mirror your actual clients—their origins, methods, headers, and auth style. Start with one of the practical examples above, tighten it to match your reality, and your CORS errors will finally stop hijacking your debugging sessions.

Explore More Building a Simple API with Node.js

Discover more examples and insights in this category.

View All Building a Simple API with Node.js