docs
  1. Developer Guide
  2. Technical Foundation
  3. Caching

Caching

Overview

This guide explains the fundamentals of caching and its implementation within the Storefront Boilerplate. Storefront Boilerplate uses hybrid rendering. This approach combines server side rendering (SSR), Single Page Application (SPA), and Static Site Generation (SSG). Depending on the page content, the most appropriate mode is chosen automatically.

Storefront Boilerplate relies heavily on server-side caching. This aims to reduce the load on the server and minimize the time and resources required to generate dynamic content for each user request. By caching the results of expensive API calls, or entire rendered pages, server-side caching optimizes response times, decreases server processing overhead, and ultimately delivers a smoother and more efficient user experience.

Before you start

Familiarize yourself with:

NitroNuxt underlying open source framework to build web servers using unjs/h3
Nitro - Storage LayerNitro has built-in integration with unjs/unstorage to provide a runtime agnostic persistent layer.
UnstorageUnified key-value storage API, supports conventional features like multi-driver mounting, watching, and working with metadata

Key concepts

Hybrid Rendering

Hybrid rendering allows different caching rules per route using Route Rules and decides how the server should respond to a new request on a given URL. Nuxt 3 includes route rules and hybrid rendering support.

Using route rules you can define rules for a group of Nuxt routes, change rendering mode, or assign a cache strategy based on route!

Hybrid rendering in detail

In Hybrid Rendering, the framework intelligently chooses between SSR and SPA based on the nature of the route. For pages that benefit from pre-rendering on the server for SEO and initial load performance, SSR is used. On the other hand, for pages where a more dynamic and interactive experience is suitable, the client-side rendering (CSR) approach of SPA is employed. This hybrid approach is designed to provide the advantages of both SSR and SPA, optimizing the balance between server-side rendering for initial page loads and client-side rendering for subsequent interactions. It helps developers achieve better performance and SEO while maintaining a dynamic user experience.

The Nuxt server of the Storefront Boilerplate will automatically register corresponding middleware and wrap routes with cache handlers using Storefront Core Cache setup based on the Nitro caching layer.

Check the latest Nuxt documentation for any changes or additions.

Route Rules

Nuxt, specifically its underlying web engine nitro allows the addition of logic at the top level of the nuxt.config.ts configuration. This is useful for redirecting, proxying, caching and adding headers to all or specific routes. By default, Nuxt uses In-Memory storage via the Nitro - Caching API for caching data internal. This applies also to data handled via routeRules if not configured differently, e.g. server-side rendered page responses.

As caching page responses purely in-memory can drastically increase the memory footprint of the runtime the Storefront application is running, the Storefront Boilerplate provides a preconfigured cache storage to be used.

Define routeRules

Nuxt also provides the option to define routeRules, called inlineRouteRules, at the page level using defineRouteRules. This feature is currently marked as experimental and must be explicitly enabled. For more details check the Nuxt - defineRouteRules documentation.

As the Storefront Boilerplate currently does not rely on features marked experimental, no direct support is provided for this feature or other experimental Nuxt features. Should you wish to use this feature, this can be implemented at your own risk!

For more in-depth details on how routeRules work check the Nitro - Route Rules documentation.

Implementation

Page caching in Storefront Boilerplate

The distributed default configuration of the Storefront Boilerplate comes with page caching enabled and relies on the global storefront-cache storage mountpoint available via Storefront Core - Caching and configured via Storefront Core - Storage via Module Configuration.

Page Caching via routeRules within the Storefront Boilerplate is enabled for all pages (see configuration key *). As not all pages should be cached, the Storefront Boilerplate explicitly disables caching for certain API or user-specific routes via cache: false.

For an in-depth overview of the available routeRule configuration options per route, check the Nuxt - Route Rule documentation.

Configure cache

cache.enabledcontrols enabling or disabling the cache. By default, it is enabled. When disabled, the cache utility will always execute the handler function and will not check the cache or save the results to the cache.
authcan be used to protect the cache control endpoints with Basic Authentication credentials.
let config = {
    cache: {
        auth: {
            username: '',
            password: '',
        },
        enabled: true
    }
}

The session configuration option session.provider is deprecated and should not be used anymore. It has been replaced by a dedicated storage.session configuration. See storage for more details.

Example
defineNuxtConfig({
    ...allOtherNuxtProjectConfiguration,
    routeRules: {
        // Page generated on-demand, revalidates in background
        '*': {
            cache: {
                swr: true, // Enable stale-while-revalidate
                maxAge: 60 * 60, // Default: 1h
                staleMaxAge: 60 * 60 * 24, // Default: 24h / 1d
                group: 'ssr', // Cache group name
                name: 'page', // Set prefix name
                // Use storefront storage mount
                // Depending on your configuration this might be `redis` or another database driver
                // https://scayle.dev/en/dev/storefront-core/module-configuration#storage
                base: 'storefront-cache',
            },
        },
        // Don't cache API routes.
        '**/api/**': { cache: false },
        '**/api/rpc/**': { cache: false },
        // Don't cache pages with user-specific information
        '**/wishlist': { cache: false },
        '**/basket': { cache: false },
        '**/checkout': { cache: false },
        '**/signin': { cache: false },
        '**/account/**': { cache: false },
        '**/orders/**': { cache: false },
    },
}

Use cache in RPC methods

The RpcContext object includes a cached function. It takes as its first argument a function to be executed, and cache options as its second argument. It returns a wrapped version of the passed-in function that caches the result of the function and will re-use the result on subsequent calls.

Available cache options

cacheKeyallows specifying an explicit cache key. If there is an entry in the cache matching cacheKey, the function will not be called and the cached result will be returned instead. If cacheKey is not passed as an option, the cache key will be automatically generated
cacheKeyPrefixis used when generating the cache key. The generated cache key will be cacheKeyPrefix concatenated with a hash of the arguments passed to the cached function.
ttldefines (in seconds) how long a cache entry should live.
timeoutallows timing out cache requests. If the cache does not return a result within the timeout period, it will execute the function instead. If timeout is not specified, a timeout of 500ms will be used. The timeout only applies to fetching from the cache
type CacheOptions = {
  cacheKey: string
  cacheKeyPrefix: string
  ttl: number
  timeout: number
}
Example RpcComtext
async function getProduct(context: RpcContext, id: number) {
  return await context.cached(context.sapiClient.products.getById, {
    cacheKeyPrefix: `getById-product-${options.id}`,
  })(options.id)
}

Disable cache

The Storefront Core internal cache, using cached can be enabled/disabled at build-time by setting the module configuration cache.enabled or at runtime via NUXT_STOREFRONT_CACHE_ENABLED.

Clear cache

The cache can be cleared by sending requests to specific endpoints.

purge/All

The /api/purge/all endpoint will clear the entire cache

curl -X POST 'http://localhost:3000/api/purge/all'

purge/tags

The /api/purge/tags endpoint will clear all cache keys for the specified tags

curl -X POST -H 'Content-type: application/json' '<http://localhost:3000/api/purge/tags>' --data '["asdf"]'

Purge Endpoint Authentication

So that random people don't invoke these endpoints, they can be protected by basic authentication. To enable basic authentication, cache.auth should be set in the module options with a username and password property. Requests will then need to include the Authorization header.

curl -X POST -H 'Authorization: Basic bWF4Om11c3Rlcm1hbm4=' 'http://localhost:3000/api/purge/all'

Test caching with Vite

Compatibility with Vite tests

Depending on the Vite test setup it might be necessary to override the default storefront.storage configuration, and to use driver: 'memory' for testing purposes.

Example pseudo test case
describe('Pseudo storefront.storage override test case', async () => {
  await setup({
    nuxtConfig: {
      storefront: {
        storage: {
          cache: {
            driver: 'memory',
          },
          session: {
            driver: 'memory',
          },
        },
      },
    },
  })

  it('renders the index page', async () => {
    // Get response to a server-rendered page with `$fetch`.
    const html = await $fetch('/')

    expect(html).toContain('<div>something</div>')
  })
})

References

Nitro

Provide Feedback