What Triggers a Preflight Request?
Understand which request characteristics cause browsers to send a CORS preflight. Learn the definition of simple requests and how to avoid unnecessary preflights.
Detailed Explanation
Simple vs. Preflighted Requests
Not every cross-origin request triggers a preflight. The browser only sends an OPTIONS request when the actual request is not simple. Understanding this distinction can help you optimize your API to avoid unnecessary round-trips.
A Request Is Simple When ALL of These Are True
- Method is
GET,HEAD, orPOST. - Headers include only CORS-safelisted headers:
Accept,Accept-Language,Content-Language,Content-Type(with restrictions),Range. - Content-Type (if present) is one of:
application/x-www-form-urlencodedmultipart/form-datatext/plain
What Triggers a Preflight
| Trigger | Example |
|---|---|
| Non-simple method | PUT, DELETE, PATCH |
| Custom header | Authorization, X-Api-Key, X-Requested-With |
| JSON Content-Type | Content-Type: application/json |
| ReadableStream body | Streaming request bodies |
Why application/json Triggers Preflight
The most common surprise: sending Content-Type: application/json — which is the norm for modern REST APIs — automatically triggers a preflight because it is not one of the three safelisted content types. This means virtually every JSON-based API call from a different origin will generate an OPTIONS request.
Avoiding Unnecessary Preflights
- For read-only endpoints, stick to
GETwith query parameters instead ofPOSTwith a JSON body. - If you control both client and server, set a generous
Access-Control-Max-Ageto cache the preflight. - Avoid adding custom headers unless necessary — each unique header combination creates a new cache key.
Checking in DevTools
Open the Network tab, enable the "All" filter, and look for pairs of requests: an OPTIONS followed by the actual method. If you see OPTIONS requests you did not expect, check which trigger condition your request matches.
Use Case
A frontend developer notices that their API calls are slow and finds that every fetch request generates a double round-trip. By switching read-only calls from POST with JSON to GET with query params, they eliminate preflights for those endpoints.