# Performance · Cache Control

## The strictest cache header wins, automatically.

Cosmo evaluates Cache-Control directives from every subgraph and applies the most restrictive policy to the response. Mutations get `no-cache`. Error responses get `no-store, no-cache, must-revalidate`. No manual coordination required.

## The problem

### Cache policies across subgraphs do not coordinate themselves

In a federated graph, each subgraph has different caching requirements. Without coordination, you get stale data, exposed sensitive fields, or missed caching opportunities.

### Subgraphs have conflicting cache requirements

Product data might be safe to cache for minutes. Pricing data should never be cached. Without coordination, setting a single policy for the whole graph means either stale data or missed caching opportunities.

### Sensitive data can leak into CDN caches

A permissive cache policy on one subgraph can expose sensitive fields to CDN caching when they appear alongside cacheable data in the same response.

### Mutations and errors are not always protected

Mutation results and error responses should never be cached. Without automatic handling, they can be served stale by CDNs or browsers.

## Our solution

### Restrictive by design

The router evaluates Cache-Control directives from every subgraph involved in a response and applies the strictest policy. You set a global default and per-subgraph overrides. The algorithm handles the rest.

### How cache policy aggregation works

1. Set `cache_control_policy.enabled: true` in your router configuration. Define a global default value, for example `max-age=180, public`.
2. Add per-subgraph overrides where specific policies are needed. A pricing subgraph might get `no-cache`; a static content subgraph might get `max-age=3600, public`.
3. On each request, the router collects Cache-Control headers from all subgraph responses involved in the query.
4. The restrictive algorithm runs: `no-cache` and `no-store` take priority over everything. The smallest `max-age` value wins. The earliest `Expires` header is used.
5. GraphQL mutations automatically receive `Cache-Control: no-cache` when a global policy is enabled, regardless of subgraph settings.
6. Responses with any errors automatically receive `Cache-Control: no-store, no-cache, must-revalidate`.

## Before & After

| Before Cosmo | With Cosmo |
| --- | --- |
| Manual cache header coordination across subgraphs | Automatic restrictive policy aggregation at the router |
| Risk of caching sensitive data when subgraphs share a response | `no-cache` and `no-store` always take precedence |
| No automatic handling of mutations | Mutations automatically receive `no-cache` |
| Error responses served stale from cache | Errors automatically receive `no-store, no-cache, must-revalidate` |

## Algorithm

### Restrictive policy rules

`no-cache / no-store`

Override all other directives. If any subgraph returns either, the response gets that directive.

`max-age`

The smallest value across all subgraphs and the global default is selected.

`Expires`

The earliest expiration timestamp wins.

## How Cache Control works in Cosmo Router

### Configure

Define a global default policy and per-subgraph overrides in your router configuration. The global value sets the baseline; subgraph values narrow it where needed.

### Evaluate

On each request, the router collects Cache-Control directives from every subgraph response that contributed to the federated result.

### Apply strictest

`no-cache` and `no-store` override everything. Among remaining directives, the smallest `max-age` wins. The earliest `Expires` header is used. Mutations get `no-cache` automatically.

### Protect errors

If the final response contains any errors, the router sets `Cache-Control: no-store, no-cache, must-revalidate` regardless of the configured policy.

## Capabilities

### Policies, overrides, and automatic protection

Global defaults, per-subgraph overrides, and automatic safety for mutations and errors.

### Global default policy

Set a baseline `Cache-Control` value for all responses. Per-subgraph overrides narrow the policy where data requires stricter caching behavior.

### Per-subgraph overrides

Configure individual subgraphs with their own cache directives. The restrictive algorithm applies the strictest setting across all subgraphs accessed by a query.

### Automatic mutation handling

When a global cache policy is enabled, GraphQL mutations automatically receive `Cache-Control: no-cache`. Mutation results are never cached.

### Error response protection

Responses with errors automatically receive `no-store, no-cache, must-revalidate`, preventing clients or CDNs from re-serving a stale error response.
