Express.js CORS Middleware Configuration

Complete guide to configuring the cors npm package in Express.js. Covers origin allowlists, dynamic origins, credentials, preflight, and per-route CORS.

Framework Config

Detailed Explanation

Express.js CORS with the cors Package

The cors npm package is the standard way to handle CORS in Express. It wraps the complexity of checking origins, setting headers, and handling OPTIONS into a clean middleware API.

Installation

npm install cors

Basic Usage — Allow All Origins

const cors = require("cors");
app.use(cors()); // Equivalent to Access-Control-Allow-Origin: *

Production Setup — Specific Origins

const corsOptions = {
  origin: ["https://app.example.com", "https://admin.example.com"],
  methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
  allowedHeaders: ["Content-Type", "Authorization", "X-Requested-With"],
  exposedHeaders: ["X-Request-Id", "X-Total-Count"],
  credentials: true,
  maxAge: 3600,
};

app.use(cors(corsOptions));

Dynamic Origin Validation

const corsOptions = {
  origin: (origin, callback) => {
    // Allow requests with no origin (e.g., mobile apps, server-to-server)
    if (!origin) return callback(null, true);

    const allowed = /^https:\/\/.*\.example\.com$/.test(origin);
    if (allowed) {
      callback(null, true);
    } else {
      callback(new Error("Not allowed by CORS"));
    }
  },
  credentials: true,
};

Per-Route CORS

// Public endpoint — wide open
app.get("/api/public", cors(), handler);

// Private endpoint — restricted
app.put("/api/private", cors(corsOptions), handler);

Middleware Order

CORS middleware must come before authentication and rate-limiting middleware. Otherwise, preflight OPTIONS requests will be rejected before CORS headers are set:

app.use(cors(corsOptions));    // 1. CORS first
app.use(rateLimiter);          // 2. Rate limiting
app.use(authMiddleware);       // 3. Authentication
app.use("/api", apiRouter);    // 4. Routes

Use Case

A Node.js backend developer setting up a new Express API that will be consumed by a React frontend hosted on a different domain. They need CORS configured correctly before the first deployment.

Try It — CORS Header Builder

Open full tool