Boost Your Web App Performance by Eliminating Unnecessary OPTIONS Calls
Learn how to improve your application's performance by understanding and avoiding unnecessary CORS preflight OPTIONS requests.

Understanding CORS Preflight Requests and Performance Optimization
Ever wonder why your application is making two HTTP requests when you only asked for one? You might be experiencing the sneaky world of CORS preflight requests! Let's dive into what these OPTIONS calls are, why they can hurt your application's performance, and how to avoid them.
What's the Deal with OPTIONS Calls?
OPTIONS requests are like your app's overly cautious friend who needs to "check if it's okay" before doing anything. When your frontend JavaScript code makes certain types of HTTP requests to a different domain, the browser first sends an OPTIONS request to ask the server "Hey, is it cool if I do this?"
This "preflight" check is part of the Cross-Origin Resource Sharing (CORS) security mechanism. While it helps keep the web secure, it can also:
- Double your API latency (waiting for OPTIONS before the real request)
- Increase your costs (especially in serverless environments where you pay per request)
- Add complexity to your server configuration
When Do OPTIONS Calls Happen?
Your browser will make these preflight requests when making cross-origin requests (requests to a different domain, protocol, or port) that are deemed "complex." These preflight checks do not happen for same-origin requests.
A cross-origin request will trigger a preflight OPTIONS request when:
- Using methods other than GET, HEAD, or POST
- Including custom headers (like
X-My-Cool-Header
) - Using content types other than:
- application/x-www-form-urlencoded
- multipart/form-data
- text/plain
How to Avoid OPTIONS Calls: The "Simple Request" Strategy
Good news! You can often avoid these preflight requests by keeping your requests "simple." Here's your handy checklist:
1. Stick to Simple Methods
// ❌ Will trigger preflight
fetch(url, { method: 'PUT' })
// ✅ No preflight
fetch(url, { method: 'POST' }) // GET and HEAD are also OK
2. Use Standard Content Types
// ❌ Will trigger preflight
fetch(url, {
headers: {
'Content-Type': 'application/json' // Always triggers preflight!
}
})
// ✅ No preflight - but data must be properly formatted
fetch(url, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: new URLSearchParams({
name: 'John',
age: '30'
}).toString()
})
Note: While using
application/json
is very common in modern web development, it will always trigger a preflight request. If performance is critical, consider using form-encoded data instead.
3. Avoid Custom Headers
// ❌ Will trigger preflight
fetch(url, {
headers: {
'X-Custom-Header': 'value'
}
})
// ✅ No preflight
fetch(url) // Using only default headers
Important Security Considerations
Before optimizing away OPTIONS requests, consider:
- Preflight requests provide important security benefits (preventing cross-site request forgery attacks)
- Only optimize if performance is a proven bottleneck
- Never put sensitive data in URL parameters just to avoid preflight
- Consider caching OPTIONS responses instead of eliminating them (note: Some browsers might ignore the cache duration completely)
Conclusion
While OPTIONS requests serve an important security purpose, they're not always necessary. By designing your API calls to be "simple requests," you can improve your application's performance and reduce costs. Just remember: keep your methods standard, your content types simple, and your headers minimal!
Remember, the best OPTIONS request is the one you never had to make! 🚀
Further Reading
Warning: Side effects of excessive OPTIONS requests may include: increased Cloud bills, slower load times, and mild developer frustration. Consult your DevOps team before proceeding. 😉
Related Articles

How to Implement Client-Side Monitoring for Web Apps
This article explores practical strategies for implementing effective client-side monitoring to enhance application performance and user experience.

TypeScript 'Satisfies' Operator: Complete Guide with Examples
Master TypeScript's 'satisfies' operator with practical examples. Learn how to improve type safety, preserve literal types, and catch errors at compile time in TypeScript development.