mrkeyoor.com_
Sun 08 Nov 22:58 UTC
npmInfraupdated 08 Nov 2026

cors review

A browser CORS error can hide a response even after your server has handled the request. cors 2.8.6 is Express/Connect middleware that sets the response headers browsers use to decide whether JavaScript may read that response. You choose origins, credential headers and preflight behavior. Authentication and authorization still belong in your application. The important setup decision is whether an origin mismatch should merely omit CORS headers or cause your own server code to reject the request.

Verdict

Use cors for an Express/Connect API when you can name the browser origins that should read each response. Start with an exact origin array and check both OPTIONS and the actual route, including whether a declined origin still reaches application code.

Answers from our run

cors or @fastify/cors: which should you use?

@fastify/cors: Choose @fastify/cors when Fastify owns your server. Its npm description identifies it as Fastify CORS; check that package's own version requirements before installing. Use cors for an Express/Connect API when you can name the browser origins that should read each response.

When should you not use cors?

You need to keep unauthorized clients out of an API. CORS headers do not authenticate callers or prevent curl from making requests.

API stability4/5The pinned implementation exports one middleware factory and supports static options, an options delegate and an origin callback. HISTORY records when preflightContinue, array origins and optionsSuccessStatus entered the API. That is a small surface with inspectable history. A 4 reflects the documented contract, not a tested promise that every Express or Node release behaves identically.
Docs4/5The release-pinned README explains the browser enforcement boundary, documents option types and covers route-level, application-level and dynamic configuration. It also contains app.del and wildcard route examples that deserve a router check before copying. A 4 credits the useful policy coverage while leaving room for clearer framework-version guidance. We did not execute its examples.
Maintenance3/5The changelog dates 2.8.6 to January 22, 2026 and lists documentation improvements and removal of additional Markdown files from the tarball. Its preceding entry is 2.8.5 from November 4, 2018. A 3 credits recorded upkeep of a narrow package while acknowledging that this release history does not establish a response-time commitment, security review or future support schedule.
Ecosystem3/5The README places cors in Express/Connect and shows middleware at application and route scope. The version-specific npm response declares object-assign and vary as runtime dependencies. Fastify and Koa each have a separately registered CORS package, so the integration boundary is concrete. A 3 reflects the documented fit for this server style; it does not infer adoption, universal framework support or tested compatibility from popularity.

Use it if

  • Your Express or Connect API needs to let a browser application on another origin read its responses.
  • Public and account endpoints need different origin and credential settings, applied through middleware or a per-request options callback.
  • You need explicit control over OPTIONS responses, allowed request headers or response headers exposed to browser JavaScript.
  • You want one reviewed middleware policy rather than repeating header assignments in route handlers.
Skip it if

Setup reality

Install the selected release with npm install cors@2.8.6 in an existing Express application. cors 2.8.6 declares object-assign and vary as runtime dependencies. This guide is based on the release-pinned documentation and implementation. We did not install the package, run these snippets or test a browser integration. The snippets are separate configuration illustrations: after the first example, app and cors refer to the initialized Express application and imported middleware. Pick the settings you need rather than stacking every example.

The default cors() policy emits a wildcard allow-origin header and finishes OPTIONS requests with status 204. That is a deliberate choice for public responses. For a named frontend, start with an array of exact origins, including the scheme and any non-default port. The implementation treats a fixed origin string differently: it writes that string even when the incoming Origin differs. An array checks membership before writing the allow-origin value. A browser may decline to expose the response in either mismatch case, but your route can still execute.

An origin callback receives the request origin and a Node-style callback. Returning callback(null, false) continues downstream without CORS headers. Passing an error calls next(error). If you need a server-side rejection, implement that requirement explicitly alongside authentication and authorization. Do not treat an origin header as proof of caller identity. Requests without an Origin header reach the callback with undefined, so decide what that means for your application's non-browser clients.

Install CORS middleware before routes that need its headers. Application-level middleware already handles preflights. If you attach it only to a GET or DELETE route, add an OPTIONS handler on the same explicit path. The pinned README contains app.del and a wildcard route example. These illustrations use app.delete and an explicit route path instead, without claiming they were tested against every Express release. Check your installed router before copying route syntax.

credentials: true emits Access-Control-Allow-Credentials. Pair it with a reviewed origin allowlist. The implementation does not reject the combination of wildcard origin and credentials for you. CORS middleware does not configure sessions or implement CSRF protection. Keep those controls in the application's security design. Dynamic origin policies also emit Vary: Origin, which matters when reviewing how your cache handles responses.

Scores below are editorial judgments from the cited documentation and source: 1 means poor fit, 2 means substantial gaps, 3 means usable with stated caveats, 4 means well supported within the inspected scope, and 5 means unusually complete evidence for that dimension. API stability assesses the documented surface and change history. Docs quality assesses coverage and copying hazards. Maintenance assesses recorded release work, while ecosystem assesses framework fit and integration boundaries. These scores do not measure security, runtime compatibility or adoption.

Patterns

Start with an exact origin array allow-exact-origins

const express = require('express')
const cors = require('cors')
const app = express()
app.use(cors({ origin: ['https://app.example.com'] }))
app.get('/api/items', (req, res) => res.json([]))
app.listen(3000)

Documentation-based illustration, not executed. An array checks the incoming origin. A fixed string writes that origin value even for a mismatching request. Neither configuration rejects the actual route by itself.

Allow public browser reads allow-public-reads

app.use(cors())

This emits Access-Control-Allow-Origin: * and handles OPTIONS by default. Use it deliberately for public responses. Do not add it ahead of a selective policy and assume the later policy removes earlier headers.

Scope middleware to an API prefix scope-api-prefix

app.use('/api', cors({ origin: ['https://app.example.com'] }))

Register this before the API routes. It applies to requests that reach the mounted middleware, including OPTIONS. It does not turn off CORS headers written elsewhere.

Use the same policy for preflight and DELETE handle-route-options

const itemCors = cors({
  origin: ['https://app.example.com'],
  methods: ['DELETE']
})
app.options('/items/:id', itemCors)
app.delete('/items/:id', itemCors, (req, res) => {
  res.json({ id: req.params.id })
})

The response only echoes an ID; it does not delete stored data. methods sets a preflight response header. It does not enforce which HTTP methods your server accepts. Authentication belongs on the actual route.

Decline an origin without raising an error decide-origin-callback

const approved = new Set(['https://app.example.com'])
app.use(cors({
  origin(origin, callback) {
    callback(null, approved.has(origin))
  }
}))

A false callback result calls next without adding CORS headers. The route may still run. This example also declines undefined, the value used when no Origin header is present. Use separate application logic if rejection is required.

Emit credentials headers for selected origins enable-credentials

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

credentials: true emits the credentials header. The library does not validate wildcard-plus-credentials configuration, configure cookies or provide CSRF defense. Keep the allowlist explicit and review the session design separately.

Declare the request headers your frontend needs set-request-headers

app.use(cors({
  origin: ['https://app.example.com'],
  allowedHeaders: ['Content-Type', 'Authorization']
}))

Without allowedHeaders, the implementation reflects Access-Control-Request-Headers and adds that field to Vary. Declaring Authorization here permits the browser header through CORS negotiation; it does not validate a token.

Expose a pagination header to JavaScript expose-response-header

app.use(cors({
  origin: ['https://app.example.com'],
  exposedHeaders: ['X-Total-Count']
}))
app.get('/items', (req, res) => {
  res.setHeader('X-Total-Count', '0')
  res.json([])
})

exposedHeaders names response headers the browser may expose. It does not create their values. Here the route sets a count matching its empty illustrative result.

Set a preflight cache header set-preflight-age

app.use(cors({
  origin: ['https://app.example.com'],
  maxAge: 600
}))

This writes Access-Control-Max-Age: 600 on OPTIONS responses. The implementation also emits a value of 0 when maxAge is 0. This setting does not configure caching for the actual JSON response.

Let a later handler finish OPTIONS continue-preflight

const continuedCors = cors({
  origin: ['https://app.example.com'],
  preflightContinue: true
})
app.options('/items', continuedCors, (req, res) => {
  res.sendStatus(200)
})

preflightContinue calls the next handler after applying CORS headers. A later handler must finish the response. If you only need a different automatic success status, set optionsSuccessStatus: 200 and leave preflightContinue false.

Alternatives

PackageRegistryPick it when
@fastify/corsnpmChoose @fastify/cors when Fastify owns your server. Its npm description identifies it as Fastify CORS; check that package's own version requirements before installing.
@koa/corsnpmChoose @koa/cors when Koa owns your server. Its npm description identifies CORS for Koa; this guide does not compare its options or performance.

More infra guides

semver · boto3 · opentelemetry-api · @opentelemetry/api · psutil · distro · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.