Access-Control-Max-Age — Caching Preflight Responses for Performance
In this tutorial, you will learn about Access. We cover key concepts, practical examples, and best practices to help you master this topic.
The Access-Control-Max-Age response header specifies how long the browser should cache the preflight response, eliminating the need for repeated OPTIONS requests for subsequent matching cross-origin requests.
What You'll Learn
- How preflight Caching improves performance
- Optimal Max-Age values and browser limits
- Security considerations for long cache durations
Why It Matters
Each preflight adds 50-200ms latency. Caching eliminates this overhead for subsequent requests. DodaTech's API uses a 2-hour cache to balance performance with security for frequently accessed endpoints.
flowchart TD
A["First request to origin"] --> B["Send OPTIONS preflight"]
B --> C["Server responds with Max-Age: 7200"]
C --> D["Browser caches preflight for 2 hours"]
D --> E["Subsequent requests to same origin"]
E --> F{"Cache still valid?"}
F -->|"Yes"| G["Skip preflight, send request directly"]
F -->|"No"| B
style D fill:#fef08a,stroke:#ca8a04
style G fill:#86efac,stroke:#16a34a
Code Examples
// Preflight caching is automatic in the browser
// You cannot control it from JavaScript
// But you can observe it in the Network tab:
// First OPTIONS request returns Max-Age
// Subsequent requests show no OPTIONS
// Measure cached vs uncached latency
const start = performance.now();
await fetch('https://api.example.com/data');
console.log('First request:', performance.now() - start, 'ms');
const start2 = performance.now();
await fetch('https://api.example.com/data');
console.log('Cached request:', performance.now() - start2, 'ms');
# Flask setting Max-Age
@app.after_request
def set_max_age(response):
if request.method == 'OPTIONS':
# Cache preflight for 1 hour
response.headers['Access-Control-Max-Age'] = '3600'
return response
// Express setting Max-Age
const cors = require('cors');
const corsOptions = {
origin: 'https://app.example.com',
methods: 'GET,POST,PUT,DELETE',
allowedHeaders: 'Content-Type,Authorization',
maxAge: 86400 // 24 hours in seconds
};
app.use(cors(corsOptions));
# Check the Max-Age header in a preflight response
curl -X OPTIONS -I \
-H "Origin: https://app.example.com" \
-H "Access-Control-Request-Method: POST" \
https://api.example.com/data | grep -i "max-age"
Common Mistakes
1. Setting Max-Age Too High
Values over 24 hours risk stale permissions if server configuration changes.
2. Setting Max-Age Too Low
Values under 60 seconds negate the caching benefit and increase preflight overhead.
3. Ignoring Browser Max-Age Limits
Chrome caps Max-Age at 600 seconds (10 min). Firefox caps at 86400 seconds (24 hours).
4. Not Setting Max-Age on Preflight Responses
Without Max-Age, the browser may still cache the preflight (default is 5 seconds in some browsers).
5. Changing Server Config Without Considering Cached Preflights
Clients may use stale cached permissions. Deploy configuration changes gradually.
Practice Questions
- What does Access-Control-Max-Age control?
- What is Chrome's maximum Max-Age value?
- What happens when Max-Age expires?
- Can JavaScript read or clear the preflight cache?
- What is a reasonable Max-Age value for production?
Answers:
- How long the browser caches the preflight response in seconds.
- 600 seconds (10 minutes).
- The browser sends a new OPTIONS preflight request.
- No. The preflight cache is managed entirely by the browser.
- 600-86400 seconds (10 min to 24 hours), depending on how often your CORS config changes.
Challenge: Measure the performance impact of different Max-Age values in a test application. Create a chart showing request latency vs Max-Age setting, and determine the optimal value for your use case.
FAQ
Mini Project
Build a preflight cache analyzer: a test page that makes repeated cross-origin requests with different Max-Age values, logs whether each request triggered a preflight, and displays the effective cache duration. Include a recommendation engine that suggests optimal Max-Age based on request frequency and CORS config change history.
What's Next
Explore the wildcard and credentials conflict to understand why these cannot be combined, then study dynamic origin whitelisting for multi-origin APIs.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro