Caching
How Easel caches static assets and dynamic HTTP responses at the CDN.
Easel can cache static files and dynamic HTTP responses so repeated requests can be served without running application code again.
Static deployment assets are handled automatically. Dynamic responses are cached when they include an eligible shared-cache policy.
Static and dynamic caching
Easel caches two broad types of content.
| Static deployment assets | Dynamic responses |
|---|---|
| Produced during the build | Produced by a function or external origin |
| Served without invoking application code | May require application code on a cache miss |
| Versioned with the deployment | Controlled by response cache headers |
| Suitable for long-lived caching | Usually use shorter, application-defined TTLs |
Examples of static deployment assets include JavaScript bundles, CSS, images, fonts, and generated HTML files.
Examples of dynamic responses include server-rendered pages, API responses, route handlers, and responses proxied from an external origin.
Cache a dynamic response
Return a shared-cache directive with a positive lifetime:
This configuration means:
- Browsers must revalidate the response.
- Easel may reuse the response for one hour.
- A later request can be served without invoking the application.
CDN-Cache-Control is the recommended header for controlling Easel’s shared
cache without changing browser behavior.
Cache-Control headers
Easel recognizes the following response headers, in descending order of precedence:
Vercel-CDN-Cache-ControlCDN-Cache-ControlCache-Control
Only the highest-priority header present is used to determine Easel’s shared-cache policy.
Portable CDN policy
Use CDN-Cache-Control when the browser and CDN should have different policies:
The browser does not retain a reusable private copy, while Easel can cache the response for ten minutes.
Vercel compatibility
Easel recognizes Vercel-CDN-Cache-Control so applications migrated from Vercel
preserve their existing CDN behavior.
When both Vercel-CDN-Cache-Control and CDN-Cache-Control are present, the
Vercel-specific header takes precedence.
Cache eligibility
A dynamic response is eligible for shared caching when all of the following are true:
- The request method is
GETorHEAD. - The response has a cacheable status.
- The selected cache policy contains a positive shared-cache lifetime.
- The response is not marked
private,no-store, orno-cache. - The response does not contain
Set-Cookie. - The request does not contain
Authorization. - The request is not a range request.
If any condition prevents caching, Easel returns:
Cacheable status codes
Easel can cache responses with these status codes:
200301302307308404
A cache policy does not make every status code cacheable.
Shared cache lifetime
Use s-maxage to define how long Easel may consider a response fresh:
The response remains fresh in the shared cache for five minutes.
When s-maxage is absent, Easel can use max-age from the selected
cache-control header.
For dynamic responses, prefer s-maxage when the browser and Easel should use
different lifetimes.
Browser and CDN caching
Browser caching and Easel caching are related but separate.
This response can be:
- reused by the browser for one minute
- reused by Easel for one hour
After the browser copy expires, the browser may request the resource again while Easel continues serving it from the CDN cache.
After the fresh lifetime
When the shared-cache lifetime ends and the response did not set
stale-while-revalidate, the next matching request waits while Easel obtains an
updated response, then stores that response if it remains eligible.
This policy means the response is fresh for 60 seconds. After that, Easel does not serve the expired entry as a cache hit.
Stale-while-revalidate
Set an explicit stale-while-revalidate window to serve the expired entry while
Easel refreshes it in the background:
With this policy:
- the response is fresh for 60 seconds (
X-Easel-Cache: HIT) - for the next 300 seconds, Easel may serve the stale body
(
X-Easel-Cache: STALE) while refreshing in the background - after that window, the next request waits for a sync refetch
Omit the directive when you want a sync refresh after the fresh TTL. Easel does
not invent a default stale window when the directive is absent. Frameworks such
as Next.js may emit stale-while-revalidate for you.
Responses that are not cached
Private responses
Do not place user-specific responses in a shared cache.
Use this for account pages, personalized API responses, authentication results, and other content that must not be reused across visitors.
Cookies
A response containing Set-Cookie bypasses shared caching.
Separate cookie-setting behavior from cacheable content when possible. For example, set the cookie on one endpoint and redirect to a cacheable page.
Authorization
Requests containing an Authorization header bypass shared caching.
This prevents authenticated responses from being reused by unrelated requests.
Range requests
Range requests bypass the shared cache. Easel does not currently serve partial
content (206) for deployment static assets.
Missing cache policy
Dynamic responses are not stored when they do not include a usable positive cache lifetime.
This response is public but does not define how long it may remain fresh.
Cache results
Easel exposes the result of cache processing through X-Easel-Cache.
| Value | Meaning |
|---|---|
HIT | A fresh cached response was served |
STALE | A stale cached response was served within an explicit stale-while-revalidate window while refreshing in the background |
MISS | No usable fresh or SWR-eligible stale entry was found |
BYPASS | The request or response was not eligible for caching |
A first request commonly returns MISS, while a later identical request returns
HIT. After the fresh lifetime, an explicit stale-while-revalidate window may
return STALE.
Example:
Treat X-Easel-Cache as the authoritative cache-result header. An Age header
may appear on some cached responses depending on the serving path; its absence
does not mean the response was uncached.
Cache keys
A cache key identifies which requests can reuse the same stored response.
Easel scopes entries to the deployment (or the hostname when deployment attribution is unavailable) and keys them by the request path and query string.
Only GET and HEAD are eligible for shared caching, so the method is not a
separate key dimension. Compression negotiation is handled by storing
uncompressed bodies and encoding on egress, so Accept-Encoding does not create
separate cache entries.
Requests with different paths or query strings are treated as different cache entries unless a documented routing or cache configuration changes that behavior.
Query strings
These URLs are distinct cache entries:
Avoid adding high-cardinality or unnecessary query parameters to cacheable URLs.
Tracking parameters can reduce cache reuse when every distinct URL creates a separate cache entry.
Vary
The Vary response header indicates that a response changes based on selected
request headers.
Use Vary carefully. Headers with many possible values reduce cache reuse.
Compression negotiation is handled automatically. Easel stores uncompressed bodies and encodes on egress, and merges:
Do not use Vary: * for cacheable responses.
Static deployment assets
Static files produced during the build are versioned with the deployment and can be served without invoking an Easel Function.
Content-hashed files such as:
can use long cache lifetimes because a changed file receives a new URL.
HTML and other route-level files may use shorter policies because their URLs commonly remain stable across deployments.
Static deployment behavior, asset headers, and deployment isolation are covered in Static files.
Framework caching
Supported frameworks can generate cache policies and revalidation metadata automatically.
Examples include:
- Next.js ISR and Cache Components
- Nuxt route rules
- SvelteKit adapter output
- framework-generated static pages
Easel maps supported framework behavior onto the CDN and Runtime Cache where appropriate.
You can still inspect the resulting HTTP policy through response headers such as:
See the relevant framework guide for framework-specific behavior.
Revalidation and purging
Expiration determines when a cached response naturally becomes stale.
Revalidation and purging allow you to refresh content earlier through:
- cache tags
- framework revalidation APIs
- supported Runtime Cache invalidation
- project cache controls
Use Revalidation and purging when content must be refreshed before its configured TTL expires.
Debugging cache behavior
Inspect the response headers:
The response is always MISS
Check that:
- the response has a positive shared-cache TTL
- repeated requests use the same hostname, path, and query string
- the response status is cacheable
- the cache entry has not expired between requests
- the deployment has not changed
The response is BYPASS
Check for:
Set-Cookie- an
Authorizationrequest header - a
Rangerequest header privateno-storeno-cache- a missing positive TTL
- an unsupported response status
The browser shows old content
The browser may be using its own cached copy even after the Easel cache has been invalidated.
Compare the browser policy in Cache-Control with the shared policy in
CDN-Cache-Control.
Use a shorter browser max-age when content must reflect CDN invalidation
quickly.
The cache contains too many variants
Inspect:
- query parameters
Vary- locale or geography-based behavior
- generated tracking parameters
- URLs that include unique identifiers
Reducing unnecessary variation increases the cache hit rate.