Skip to article
TOOLS. SYSTEMS. BETTER DECISIONS.
Stack & Method

The journal

Preflight vs XHR: what’s the difference?

A clear, practical explanation of how a CORS preflight (OPTIONS) differs from an XMLHttpRequest (XHR), when browsers send preflights, and how that affects your requests.

Minimal conceptual network list with a translucent support colored preflight row before a primary colored xhr row

A CORS preflight is an automatic HTTP OPTIONS request the browser sends to check cross-origin permissions; XMLHttpRequest (XHR) is the JavaScript API that performs the actual HTTP request. If the preflight is denied, the browser does not send the actual cross-origin HTTP request. See MDN: Preflight request and MDN: XMLHttpRequest.

How a CORS preflight works

When a cross-origin request is not considered “simple,” the browser automatically issues a preflight. This is a CORS request using the OPTIONS method that asks the server whether the intended method and headers are allowed. The browser includes:

  • Origin
  • Access-Control-Request-Method (the method it intends to use)
  • Access-Control-Request-Headers (optional list of request header names)

If the server permits the request, it responds with CORS headers such as Access-Control-Allow-Origin, Access-Control-Allow-Methods, and (when relevant) Access-Control-Allow-Headers. The browser may cache the preflight decision using Access-Control-Max-Age in a dedicated preflight cache (not the general HTTP cache). Source: MDN: Preflight request.

Minimal sequence diagram showing browser preflight OPTIONS request then server CORS allow response then browser XMLHttpRequest or fetch

What XHR is (and is not)

XMLHttpRequest is the client API used to send the actual HTTP request and receive a response. It can make same-origin or cross-origin calls, but permission for certain cross-origin calls is enforced by the browser via the preflight step. XHR itself does not negotiate CORS rules; it is just the transport used after the browser allows the request. Source: MDN: XMLHttpRequest.

Typical sequence you’ll see in DevTools

  • Browser sends OPTIONS (preflight) with the intended method and headers.
  • Server replies with Access-Control-Allow-* headers that must permit the origin, method, and any non-simple headers.
  • If allowed, the browser proceeds to send the actual XHR (or other client API) request; if not, the browser blocks it and reports a CORS error. Source: MDN: Preflight request.

What triggers a preflight (and how to avoid unnecessary ones)

Preflights occur for non-simple cross-origin requests. Common triggers include:

To avoid avoidable preflights, keep cross-origin requests within “simple” constraints where that’s acceptable and remove unnecessary custom headers. Otherwise, configure your server to reply correctly to the preflight.

Diagnose and fix a blocked cross-origin XHR

Example: adding a custom header

If your client adds a header such as X-Requested-With, the browser will preflight. The preflight includes Access-Control-Request-Headers: X-Requested-With, and the server must reply allowing that header via Access-Control-Allow-Headers. Only after a permitting response does the browser send the actual XHR. Source: MDN: Preflight request.

Unbranded 2D vector network panel showing OPTIONS response headers as unlabeled rows with blue and yellow accents

Related reading on Stack & Method

Short FAQ

Does preflight happen for same-origin calls?
No. A preflight is a CORS request and only applies to cross-origin conditions. Source: MDN: Preflight request.

Is preflight tied to XHR only?
No. Preflight is a browser behavior for qualifying cross-origin requests. XHR is just one way to send the actual request afterward. Source: MDN: Preflight request, MDN: XMLHttpRequest.

Stack & Method logo

In practice: inspect the OPTIONS preflight first, correct the server’s Access-Control-Allow-* headers, then retry the actual XHR once the browser grants permission.

Sources and further reading

Your privacy choices

Optional analytics helps us improve these guides. It stays off until you allow it. Privacy details