How to Manage CORS Policy Properly in Express with the cors Middleware

Use the cors npm package as middleware in your Express application to handle Cross-Origin Resource Sharing headers and pre-flight requests automatically.

Express does not implement CORS internally; you must add the cors module to manage cross-origin policies correctly. According to the expressjs/express source code, the framework relies on external middleware for CORS handling, with the cors package being the community standard for configuring Access-Control-* headers and OPTIONS pre-flight responses.

Why Express Requires an External CORS Module

The core Express library focuses on routing and middleware orchestration, not protocol-level concerns like CORS. As shown in the repository's package.json, CORS support is listed as an optional dependency rather than a built-in feature. The dedicated cors middleware implements the full W3C CORS specification, validates origin inputs to prevent security mistakes, and handles complex pre-flight scenarios that would require significant boilerplate if implemented manually.

Installing and Mounting the CORS Middleware

Install the package via npm:

npm install cors

Mount the middleware early in your application stack using app.use(). In lib/application.js (lines 190‑226), Express implements the use method to register middleware that processes every incoming request. Positioning CORS at the top ensures the middleware sets headers before your route handlers execute.

const express = require('express')
const cors = require('cors')

const app = express()

// Mount CORS before route definitions
app.use(cors())

app.get('/data', (req, res) => {
  res.json({ message: 'CORS headers already set' })
})

Configuring CORS Policy Options

The cors() function accepts an options object that maps directly to standard CORS headers. These settings control which origins, methods, and headers your Express application permits.

Controlling Allowed Origins

The origin option accepts a string, regular expression, or function to validate request origins. Set it to a specific domain for strict control, or use a function to implement dynamic whitelist logic against a database.

// Allow only example.com
app.use(cors({ origin: 'https://example.com' }))

// Dynamic validation with callback
const whitelist = ['https://example.com', 'https://app.example.org']

app.use(cors({
  origin: (origin, callback) => {
    if (!origin || whitelist.includes(origin)) {
      callback(null, true)
    } else {
      callback(new Error('Not allowed by CORS'))
    }
  }
}))

Specifying HTTP Methods and Headers

Use methods to whitelist HTTP verbs and allowedHeaders to permit custom request headers. The exposedHeaders option determines which response headers the browser should expose to the client-side script.

app.use(cors({
  methods: ['GET', 'POST', 'PUT'],
  allowedHeaders: ['Content-Type', 'Authorization'],
  exposedHeaders: ['X-Total-Count']
}))

Enabling Credentials and Pre‑Flight Behavior

Set credentials: true to allow cookies and authorization headers in cross-origin requests. The preflightContinue option determines whether the middleware passes OPTIONS requests to subsequent handlers or terminates them automatically.

app.use(cors({
  origin: 'https://trusted-site.com',
  credentials: true,
  preflightContinue: false  // Automatically respond to OPTIONS
}))

Handling Pre‑Flight OPTIONS Requests

When you mount the cors middleware, Express automatically responds to OPTIONS pre-flight requests with the appropriate Access-Control-* headers. This behavior is documented in the repository's History.md (line 2843), which notes the addition of automatic OPTIONS handling for CORS scenarios.

No manual route definition is required unless you need custom logic for specific endpoints.

Manual Pre‑Flight Handling

For rare cases requiring additional processing during pre-flight, explicitly handle OPTIONS while keeping the CORS middleware active:

app.options('/special-resource', cors(), (req, res) => {
  console.log('Pre-flight from:', req.get('Origin'))
  res.sendStatus(204)   // the cors middleware already set the needed headers
})

Applying CORS Globally vs. Per‑Route

You can apply CORS settings application-wide or restrict them to specific routes based on security requirements.

Global application uses app.use(cors()) before route definitions, as shown in previous examples.

Route‑Specific CORS Configuration

Attach the middleware directly to route definitions to override global settings or protect sensitive endpoints:

// Public endpoint – open to all origins
app.get('/public', cors(), (req, res) => {
  res.json({ data: 'Public information' })
})

// Admin endpoint – strict origin validation with credentials
app.get(
  '/admin',
  cors({
    origin: 'https://admin.example.com',
    credentials: true
  }),
  (req, res) => {
    res.json({ data: 'Sensitive admin data' })
  }
)

Summary

  • Express does not include CORS handling in its core; you must install the cors middleware package.
  • Mount the middleware early using app.use() (implemented in lib/application.js lines 190‑226) to ensure headers are set before route logic executes.
  • Configure policies via the options object to control allowed origins, methods, headers, and credentials.
  • Pre‑flight requests are handled automatically when the middleware is active, as noted in the repository's History.md.
  • Apply globally or per‑route depending on whether endpoints require public access or strict origin validation.

Frequently Asked Questions

How do I enable CORS for all origins in Express?

Use the default cors() middleware without options. Mount it with app.use(cors()) at the top of your middleware stack. This sets Access-Control-Allow-Origin: * and allows all standard HTTP methods.

Why is my Express API blocking cross‑origin requests even after adding the cors middleware?

Ensure you mounted the middleware before defining routes. In lib/application.js, Express processes middleware in the order registered via app.use(). If routes are defined first, they execute before CORS headers are set. Also verify that your origin option does not exclude the requesting domain.

Can I allow multiple specific origins with the Express cors module?

Yes. Provide a function to the origin option that checks the requesting origin against your whitelist array. Return callback(null, true) for allowed origins or callback(new Error('Not allowed by CORS')) for rejected ones. This approach supports dynamic, database‑driven origin validation.

Does the Express cors middleware handle pre‑flight OPTIONS requests automatically?

Yes. When mounted, the middleware intercepts OPTIONS requests and responds with appropriate Access-Control‑Allow‑* headers without reaching your route handlers. This behavior is documented in the Express repository's History.md. You only need manual OPTIONS handling if you require custom logic during the pre‑flight phase.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →