Skip to main content

Web App Caching and Performance Configuration

This guide explains how to configure caching and performance settings for a self-hosted web app.

It is written for customers, implementation engineers, and CDN/infrastructure teams configuring production environments.

Use this guide to configure:

  • Zapp caching settings
  • Environment variables
  • CDN / CloudFront cache behavior
  • Redis-related runtime settings
  • Feed timeout behavior

For full self-hosting infrastructure requirements, see Web Hosting Guidelines.


Configuration Areas

Caching and performance are configured in three places.

AreaWhat it controls
ZappFeed rendering behavior, Feed Server Abort Timeout, component-level loading behavior
Environment variablesRuntime caching behavior, Redis behavior, user-group cache behavior
CDN / CloudFrontCache keys, TTLs, route bypass rules, forwarded headers/cookies/query strings

Use this rule:

Zapp controls how the app renders. Environment variables control runtime behavior. CDN controls which responses can be reused.


For most apps, start with this setup.

Zapp

Enable Feed Server Abort Timeout: true
Timeout: 1500 ms

Environment Variables

CONFIGS_TTL=300
CONFIGS_SWR=3600
CLIENT_LOADED_FEEDS_ABORT_TIMEOUT_MS=10000

Optional, depending on deployment:

REDIS_TLS=true
REDIS_USE_CLUSTER=true
NO_INDEX=true

Use CACHING_GROUP_COOKIE only when the server-rendered page changes for a small, fixed set of user groups, such as anonymous users, logged-in users, premium users, or non-premium users.

CACHING_GROUP_COOKIE=<access-token-claim-name>

CDN / CloudFront

For cacheable page routes:

Cache query strings: all
Cache cookies: none by default
Cache headers:
- CloudFront-Viewer-Country only if SSR differs by country
- CloudFront-Viewer-Time-Zone only if SSR differs by time zone

For user-specific, auth, payment, and player routes:

Disable caching
Forward required cookies
Forward Set-Cookie from origin to browser
Respect origin Cache-Control

Feature Configuration

1. Feed Server Abort Timeout

Feed Server Abort Timeout prevents slow server-side feed requests from blocking page rendering.

If a feed exceeds the configured timeout:

  • The feed request is aborted on the server
  • The page continues loading
  • The feed is loaded from the client after the page loads

This is useful when one slow feed can delay the full SSR response.

When to Use It

Use Feed Server Abort Timeout when:

  • A page contains multiple feeds
  • Some feeds are slow or unreliable
  • First page load is too slow
  • SSR is important, but the page should not wait indefinitely for every feed
  • A slow feed can be loaded after the page appears

Zapp Configuration

In the Caching plugin:

Enable Feed Server Abort Timeout: true
Timeout: 1500 ms

Recommended values:

App behaviorTimeout
Default starting point1500 ms
Mostly stable VOD/catalog app1500 ms
News, sports, or frequently updated app1000–1500 ms
First paint is more important than SSR completeness1000 ms
No known performance issue2000–3000 ms

Avoid:

  • 100 ms, because it may abort too many feeds
  • Values below 500 ms, unless specifically advised
  • 5000 ms, because it usually gives little performance benefit

2. Client-Loaded Feed Timeout

CLIENT_LOADED_FEEDS_ABORT_TIMEOUT_MS controls how long client-loaded feed requests can run before being aborted in the browser.

This applies to feeds that are loaded from the client, including feeds that load from the client after server-side loading was aborted.

When to Use It

Use this setting when:

  • Client-loaded feeds sometimes hang
  • A slow feed hurts the browser experience
  • You want to show fallback or empty states instead of waiting too long
  • The app uses client-side feed loading for dynamic or frequently updated content

Environment Variable

Recommended starting value:

CLIENT_LOADED_FEEDS_ABORT_TIMEOUT_MS=10000

This allows client-loaded feeds to run for up to 10 seconds.

Use a shorter value, such as 5000, when:

  • Feeds are often slow
  • The page has many feeds
  • The UX should fail fast

Use a longer value only when:

  • Feed providers are slow but usually return valid data
  • The feed is important enough to wait for
  • Users are expected to have slower network conditions

3. Configuration Cache TTL and SWR

Configuration data is cached to reduce origin work and improve response time.

Two environment variables control this behavior:

CONFIGS_TTL=300
CONFIGS_SWR=3600

CONFIGS_TTL

CONFIGS_TTL controls how long configuration data is considered fresh.

Example:

CONFIGS_TTL=300

This means config data can be treated as fresh for 300 seconds.

Use a shorter TTL when:

  • Configuration changes must appear quickly
  • The customer frequently updates layout, navigation, or content configuration
  • You are testing in staging

Use a longer TTL when:

  • Configuration changes are infrequent
  • Traffic is high
  • Reducing origin/cache refresh pressure is more important than immediate freshness

CONFIGS_SWR

CONFIGS_SWR controls how long stale configuration data can be reused while fresh data is revalidated.

Example:

CONFIGS_SWR=3600

This allows stale config to be served while the app refreshes config in the background.

Use a longer SWR window when:

  • Availability is more important than immediate freshness
  • The app should keep serving pages if config refresh is slow
  • The configuration source may occasionally be unavailable

Use a shorter SWR window when:

  • Stale configuration is unacceptable
  • The customer frequently changes app structure or navigation

Recommended starting point:

CONFIGS_TTL=300
CONFIGS_SWR=3600

4. CDN Page Caching

The CDN is the main caching layer for HTML documents and static assets.

Most performance gains should come from CDN cache hits.

Default Rule

For cacheable page routes, use the smallest cache key that still returns correct content.

Include:

URL path
Query string
Country header, only if content differs by country
Time zone header, only if content differs by time zone
caching-group-cookie, only if SSR output differs by entitlement group

Do not include:

Full Cookie header
Session cookies
JWT cookies
User ID
Favorites state
Continue Watching state
Analytics cookies
Third-party cookies

CloudFront Default Page Cache Policy

Use this for most cacheable page routes.

Query strings in cache key: all
Cookies in cache key: none
Headers in cache key:
- none by default
- CloudFront-Viewer-Country only if SSR differs by country
- CloudFront-Viewer-Time-Zone only if SSR differs by time zone
Compression: enabled

Origin request policy:

Forward query strings: all
Forward cookies: none
Forward headers:
- CloudFront-Viewer-Country only if the app needs it
- CloudFront-Viewer-Time-Zone only if the app needs it

When to Use Short CDN TTL

Use a short CDN TTL for pages that change frequently but can tolerate brief staleness.

Examples:

  • News pages
  • Sports schedules
  • Recently updated rails
  • Live-event listing pages

CloudFront cache policy:

Minimum TTL: 0
Default TTL: short
Maximum TTL: short
Query strings in cache key: all
Cookies in cache key: none by default
Headers in cache key:
- CloudFront-Viewer-Country only if needed
- CloudFront-Viewer-Time-Zone only if needed

For highly dynamic content, prefer:

Cache page shell at CDN
Load fast-changing feeds from the client
Keep real-time APIs non-cacheable or short-lived

5. User-Group Cache Variation

Use user-group cache variation only when the SSR document changes by entitlement or login group.

Examples:

  • Premium users see different SSR content than non-premium users
  • Anonymous users see different SSR page structure than logged-in users
  • Server-rendered metadata differs by subscription tier
  • Premium shelves are rendered during SSR only for premium users

Do not use this for per-user personalization.

Environment Variable

Configure:

CACHING_GROUP_COOKIE=<access-token-claim-name>

Example:

CACHING_GROUP_COOKIE=subscription_tier

The access-token claim should produce low-cardinality values.

Good values:

anonymous
registered
premium
non-premium
vip
kids

Bad values:

user_id
email
session_id
jwt_id
device_id

If CACHING_GROUP_COOKIE is not configured:

  • The app does not produce caching-group-cookie
  • The CDN must not depend on it

CloudFront Configuration

Use this only for cacheable page routes where SSR differs by group.

Cache policy:

Query strings in cache key: all
Cookies in cache key:
- caching-group-cookie
Headers in cache key:
- CloudFront-Viewer-Country only if needed
- CloudFront-Viewer-Time-Zone only if needed

Origin request policy:

Forward query strings: all
Forward cookies:
- caching-group-cookie
Forward headers:
- CloudFront-Viewer-Country only if used
- CloudFront-Viewer-Time-Zone only if used

Never include:

Full Cookie header
Session cookie
JWT cookie
User ID

Rule of thumb:

Use caching-group-cookie for groups, not users.


6. Country and Time-Zone Variation

Use country or time-zone variation only when the SSR document changes based on country or time zone.

Country Variation

Use this when:

  • Catalog differs by country
  • Availability differs by country
  • Regional rails differ by country
  • Geo-blocking affects SSR output

CloudFront header:

CloudFront-Viewer-Country

Vercel header:

x-vercel-ip-country

CloudFront cache policy:

Headers in cache key:
- CloudFront-Viewer-Country

Origin request policy:

Forward headers:
- CloudFront-Viewer-Country

Do not vary by country if the page shell is identical and regional data loads from the client.

Time-Zone Variation

Use this when:

  • Broadcast schedules differ by time zone
  • Live sports schedules differ by time zone
  • Time-windowed availability affects SSR output
  • “Available today” content differs by local time

CloudFront header:

CloudFront-Viewer-Time-Zone

Vercel header:

x-vercel-ip-timezone

CloudFront cache policy:

Headers in cache key:
- CloudFront-Viewer-Time-Zone

Origin request policy:

Forward headers:
- CloudFront-Viewer-Time-Zone

Do not vary by time zone if schedule data loads from the client.


7. Non-Cacheable Routes

Some routes must never be cached by CDN because they are user-specific, state-changing, or security-sensitive.

CDN / CloudFront Configuration

For these routes:

Disable caching
Forward required cookies
Forward required query strings
Forward Set-Cookie from origin to browser
Respect origin Cache-Control
Allow required HTTP methods

At minimum, support:

GET
POST
OPTIONS

Routes to Bypass

Authentication and session:

/api/is-logged-in
/api/logout
/api/oauth
/login
/login/token
/logout
/oauth
/users/sign_in
/users/login
/users/password/edit

Payment and billing:

/payment
/billing
/api/payment-auth
/api/stripe-create-payment-session
/api/stripe-billing-portal
/successful-payment
/paypal-purchase

User-specific data:

/api/favorites
/api/favorite-action
/api/continue-watching
/api/client-feed
/api/preference-editor
/api/maybe-redirect

Player:

/player

Parental controls:

/lock
/parent-lock

8. Personalized Features

Features such as Continue Watching, Favorites, profile state, and personal recommendations should not define the page cache key.

Recommended setup:

Keep page/document routes shared and cacheable
Render personal widgets after page load
Fetch personal data from non-cacheable APIs
Do not vary CDN cache by user ID, session, JWT, favorites, or watch history

Use CACHING_GROUP_COOKIE only for low-cardinality entitlement groups, not personalization.


9. Redis Configuration

Redis is used for:

  • Caching Zapp configuration JSONs
  • Caching content feeds
  • Storing user JWTs

Optional Redis variables:

REDIS_TLS=true
REDIS_USE_CLUSTER=true

Use REDIS_TLS=true when the Redis provider requires TLS.

Use REDIS_USE_CLUSTER=true when Redis Cluster is used.

Redis should be located in the same region as the origin server when possible.

Clearing Redis may log out users because JWTs are stored there.


10. Staging Configuration

For staging environments, configure:

NO_INDEX=true

Use this to prevent SEO bots from indexing staging deployments.

Staging should mirror production as closely as possible so caching and performance behavior can be tested before production release.


CloudFront Behavior Summary

Configure CloudFront with separate behaviors for different route types.

PriorityBehaviorExample path patternCache setup
1Auth/session routes/login*, /logout*, /oauth*, /users/*Disabled caching
2Payment routes/payment*, /billing*, payment APIsDisabled caching
3User-specific APIs/api/favorites*, /api/continue-watching*Disabled caching
4Player routes/player*Disabled caching
5Static assets/_next/static/*, /assets/*, *.js, *.cssLong-lived caching
6Page/document routesDefault behaviorCustom page cache policy

More specific behaviors should have higher priority than the default behavior.


Static Assets CloudFront Policy

Use this for JavaScript, CSS, images, fonts, and other static assets.

Minimum TTL: 0
Default TTL: 86400
Maximum TTL: 31536000
Query strings in cache key: all
Cookies in cache key: none
Headers in cache key: none, except normalized Accept-Encoding when compression is enabled
Compression: enabled

Do not forward cookies for static assets.


Testing Checklist

Before production release, verify:

Zapp

  • Feed Server Abort Timeout is enabled when needed
  • Timeout value matches the app behavior
  • Slow or non-critical feeds are loaded from the client when appropriate
  • Personalized widgets are not unnecessarily part of SSR output

Environment Variables

  • CONFIGS_TTL is configured
  • CONFIGS_SWR is configured
  • CLIENT_LOADED_FEEDS_ABORT_TIMEOUT_MS is configured
  • CACHING_GROUP_COOKIE is configured only when SSR differs by user group
  • CACHING_GROUP_COOKIE does not use user ID, email, session ID, or device ID
  • REDIS_TLS=true is set if Redis requires TLS
  • REDIS_USE_CLUSTER=true is set if Redis Cluster is used
  • NO_INDEX=true is set for staging

CDN / CloudFront

  • Static assets have a dedicated cache behavior
  • Cacheable page routes use a custom page cache policy
  • Auth routes bypass cache
  • Payment routes bypass cache
  • User-specific API routes bypass cache
  • Player routes bypass cache
  • Query strings are included for page/document routes
  • Full Cookie header is not included in the cache key
  • caching-group-cookie is included only when SSR differs by user group
  • Session and JWT cookies are not included in the cache key
  • Country header is included only when SSR differs by country
  • Time-zone header is included only when SSR differs by time zone
  • Set-Cookie from origin reaches the browser on auth/session routes
  • Origin Cache-Control headers are respected

Related Documentation

For full self-hosting CDN cache-key guidance, cookie-based variation, non-cacheable route handling, Redis configuration, server requirements, and infrastructure requirements, see Web Hosting Guidelines.