Skip to main content
CDN

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 assetsDynamic responses
Produced during the buildProduced by a function or external origin
Served without invoking application codeMay require application code on a cache miss
Versioned with the deploymentControlled by response cache headers
Suitable for long-lived cachingUsually 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:

Cache-Control: public, max-age=0, must-revalidate
CDN-Cache-Control: public, s-maxage=3600

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:

  1. Vercel-CDN-Cache-Control
  2. CDN-Cache-Control
  3. Cache-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:

Cache-Control: private, max-age=0
CDN-Cache-Control: public, s-maxage=600

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.

Vercel-CDN-Cache-Control: public, s-maxage=3600

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 GET or HEAD.
  • The response has a cacheable status.
  • The selected cache policy contains a positive shared-cache lifetime.
  • The response is not marked private, no-store, or no-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:

X-Easel-Cache: BYPASS

Cacheable status codes

Easel can cache responses with these status codes:

  • 200
  • 301
  • 302
  • 307
  • 308
  • 404

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:

CDN-Cache-Control: public, s-maxage=300

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.

CDN-Cache-Control: public, max-age=300

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.

Cache-Control: public, max-age=60
CDN-Cache-Control: public, s-maxage=3600

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.

CDN-Cache-Control: public, s-maxage=60

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:

CDN-Cache-Control: public, s-maxage=60, stale-while-revalidate=300

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.

Cache-Control: private, no-store

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.

Set-Cookie: session=...

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.

Cache-Control: public

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.

ValueMeaning
HITA fresh cached response was served
STALEA stale cached response was served within an explicit stale-while-revalidate window while refreshing in the background
MISSNo usable fresh or SWR-eligible stale entry was found
BYPASSThe 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.

curl -I https://example.com/products
curl -I https://example.com/products

Example:

HTTP/2 200
CDN-Cache-Control: public, s-maxage=300
X-Easel-Cache: HIT

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:

/products?page=1
/products?page=2

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.

Vary: Accept-Language

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:

Vary: Accept-Encoding

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:

/assets/app.9f3ac21.js

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:

Cache-Control
CDN-Cache-Control
X-Easel-Cache

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:

curl -I https://example.com

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 Authorization request header
  • a Range request header
  • private
  • no-store
  • no-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.