Menu Sheet Overlay

Server-Side Rendering Performance: Using Mobify's Application Cache to Boost PWA Performance

Note: The Server-Side Rendering Performance series is designed to dive into the most important topics you'll encounter while building, testing and deploying a server-side rendered Progressive Web App (PWA). To learn how these PWAs differ from Mobify’s tag-loaded PWAs, read our overview.

How Mobify’s Application Caching works

Note: For an introduction to Mobify's Application Cache, read an overview.

Unlike the CDN cache, which maps URLs to cache entries using cache control response headers, the Application Cache must be called from code in the SSR server.

The Application Cache supports the CDN Cache, adding a different caching design to optimize responses to web crawlers:

  • Providing abundant, guaranteed storage: sometimes, the CDN Cache may evict an item from its cache before the item expires, in favour of a newer, more frequently-accessed item. While this is optimal for real users, it’s not ideal for web crawlers, which may request random, infrequently-accessed content. The Application Cache provides guaranteed storage. When you put something inside the Application Cache, it’s guaranteed to stay until its expiry.

  • Providing one global cache: while the CDN Cache provides a number of separate regional caches, the Application Cache has just one global cache per target. The CDN Cache design is optimized for speed. However, this comes at the cost of having to render a page again for each region, even if it’s been cached in another region. With the Application Cache, when a page is cached in one region, it’s cached for all regions. This is ideal for responses to web crawlers, because we would expect all repeat visits to a URL to be significantly faster, instead of just repeat visits to a URL within the same region.

  • Storing HTTP responses and more: unlike the CDN Cache, the Application Cache can store much more than HTTP responses. For example, you can use the Application Cache to store data, in order to avoid network calls to an ecommerce backend.

Similar to the CDN Cache, by default, the Application Cache also stores different versions of the response based on device type-- mobile, desktop, or tablet.

Because it uses a different storage mechanism than the CDN Cache, it must be cleared separately.

Maximizing performance by using Mobify’s Application Cache

Using the Application Cache to Store HTTP Responses

Using the Application Cache together with the CDN Cache will further improve your PWA’s response times, in particular for web crawlers.

The Application Cache provides a high level API to get, send and store responses. The following methods are documented in our SSR Server API Docs:

  • SSRServer.getResponseFromCache(): retrieves a response from the cache, returning a Promise.
  • SSRServer.sendCachedResponse(): sends a response that's been retrieved from the cache.
  • SSRServer.cacheResponseWhenDone(): puts a response in the cache.

These are typically used in the requestHook of the SSR server. Let’s illustrate with an example:

// packages/pwa/app/ssr.js
const {SSRServer} = require('progressive-web-sdk/dist/ssr/ssr-server')

class ExtendedSSRServer extends SSRServer {
    requestHook(request, response, next) {
        const namespace = `v1`
        this.getResponseFromCache({ request, response, namespace }).then(
            entry => {
                // Respond with the cached version
                if (entry.found) {
                    return this.sendCachedResponse(entry)

                // Otherwise, render and cache the result


Keys for the Application Cache are generated from requests by default. The keys take into account:

  • The request path (lowercase)
  • The device type (mobile, tablet, or desktop)
  • The request class

You can think of the namespace as a prefix which is appended to the key. If you change it, it effectively invalidates the cache: all lookups will now be use different keys.

By default, cacheResponseWhenDone uses the HTTP cache control header of your response to determine how long to store something. You can override this by passing a different expiration value to the function.

You can see whether a response was retrieved from the Application Cache by checking whether x-mobify-from-cache: true is present in the response headers.

When using the Application Cache, you’ll need to consider:

  • Which responses should be cached, and for how long? Remember not to store personalized or frequently-changing information.
  • Should errors should be cached? (If you need to choose whether to cache errors, pass a shouldCacheResponse function to cacheResponseWhenDone)
  • What is an appropriate expiration date and time for entries in the cache? (See our API documentation for SSR Server method cacheResponseWhenDone). For example, you might choose to set the cache expiration to 24 hours so that a cached response will be regenerated daily.
  • How to invalidate the cache? Deleting the entire Application Cache can be a slow operation. It's much more effective to change the namespace used to look up entries; this effectively invalidates the cache. You may also want to invalidate specific cache entries. You can do this by changing the cache key used (see the documentation for getResponseFromCache). If you have access to a "version number" of the backend data used to generate a particular response, then including that version number in the cache key will cause the key to change when the version does.

Using the Application Cache to store data required to build a response

Another use of the Application Cache is to store data required to build a response, in order to avoid making network calls to the ecommerce backend. Stay tuned for a future tutorial where we’ll demonstrate this use of the Application Cache.

Next steps

Next, you can continue through our Server-Side Rendering Performance series, with an article about testing and debugging your local SSR backend. Or, explore best practices to optimize your PWA’s client-side performance.



Was this page helpful?