Web Security: CORS Preflight Requests (OPTIONS)
When building web applications, you often fetch data from external APIs hosted on different domains. To protect users from malicious requests, browsers enforce a security mechanism called Cross-Origin Resource Sharing (CORS).
A common bottleneck in API performance is the CORS Preflight Request. Understanding what triggers preflights and how to avoid them is a key topic in senior frontend interviews.
1. What is a CORS Preflight Request?
A preflight request is a preliminary check sent by the browser to the target server before sending the actual HTTP request.
The browser uses the OPTIONS method to ask the server for permission:
"Hey, I'm about to send a POST request with a custom JSON payload and an Authorization header from site-a.com. Do you support this?"
The server must respond with the correct headers (like Access-Control-Allow-Origin and Access-Control-Allow-Headers). If it does, the browser proceeds to send the actual request. If the server rejects the preflight, the browser blocks the actual request.
2. "Simple" vs "Preflighted" Requests
Not all API requests trigger a preflight. The browser classifies requests into two categories:
Simple Requests (No Preflight)
A request is considered "simple" and skips the preflight if it satisfies all of the following:
- HTTP Method: Must be
GET,HEAD, orPOST. - Content-Type Header: Must be only one of:
application/x-www-form-urlencodedmultipart/form-datatext/plain
- No Custom Headers: Cannot include custom headers like
AuthorizationorX-Custom-Header.
Preflighted Requests (Triggers Preflight)
If the request violates any of the rules above, the browser triggers a preflight. This includes:
- Sending a JSON payload (
Content-Type: application/json). - Using methods like
PUT,DELETE,PATCH. - Adding credentials or token headers (e.g.,
Authorization).
3. The Performance Impact of Preflight
Preflight requests add an extra HTTP round-trip (OPTIONS) before your actual API call.
Client ➔ OPTIONS (Preflight) ➔ Server
Client 🦄 Access Approved 🦄 Server
Client ➔ POST (Actual Request) ➔ Server
Client 🦄 Response Received 🦄 Server
This effectively doubles the latency of your API requests. If your server is physically far away, this preflight check can add 100ms to 300ms of lag on every user action.
4. How to Optimize or Avoid Preflight
Solution A: Enable Preflight Caching (Access-Control-Max-Age)
You can tell the browser to cache the preflight response so it doesn't send an OPTIONS request every time. The server must return the Access-Control-Max-Age header specifying the cache duration in seconds.
# Server response to OPTIONS preflight
Access-Control-Allow-Origin: https://site-a.com
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: Authorization, Content-Type
Access-Control-Max-Age: 86400 # Cache this preflight check for 24 hoursDuring this 24-hour window, the browser will send the actual request immediately without the preliminary OPTIONS check.
Solution B: Same-Origin Routing (Reverse Proxy)
The cleanest way to avoid CORS checks altogether is to make your API requests same-origin. You can set up a reverse proxy on your frontend server (such as Next.js rewrites or Cloudflare rules) to route requests to the API.
Instead of calling https://api.myapp.com/v1/users (triggers CORS), the client calls /api/v1/users (same-origin). The frontend server proxies this request in the background where CORS rules do not apply.
Key Takeaways
- A CORS preflight request is an HTTP
OPTIONScheck sent automatically by the browser to verify security permissions on cross-origin calls. - Preflights are triggered by
application/jsoncontent types, custom headers (likeAuthorization), or non-simple HTTP methods (PUT,DELETE). - Preflight requests double network latency by adding an extra connection round-trip.
- Optimize preflight overhead by enabling caching with the
Access-Control-Max-Ageheader or routing requests through a same-origin proxy to bypass CORS checks.