Nuxt Multi Cache

repository·main·Indexed 43 days ago

https://github.com/dulnan/nuxt-multi-cache

A multi-layered server-side caching module for Nuxt 3 and 4 (version 4.0.3). It provides tools for caching SSR components via <RenderCacheable>, routes and API responses using useRouteCache, and generic data with useDataCache. It also includes useCDNHeaders for managing CDN cache control headers and supports key-based and tag-based invalidation using unstorage backends like Redis.

Tokens
36.4K
Snippets
119
Records
151
Agent score
54%

What's inside Nuxt Multi Cache

  1. Overview of Nuxt Multi Cache features

    main

    Nuxt Multi Cache is an advanced caching solution for Nuxt applications that provides four primary capabilities:

    • Component Cache: Caches the rendered markup of components to significantly reduce server-side rendering (SSR) time.
    • Route Cache: Caches the full response of pages or custom API routes, including HTTP headers.
    • Data Cache: A generic composable used to cache arbitrary data, such as external API responses or expensive computations.
    • CDN Headers: Allows dynamic management of Cache-Control or Cache-Tag HTTP headers for edge caches like Cloudflare, Fastly, or Varnish.

    It also provides a cache management API for purging specific items by key or using cache tags.

  2. Configure a cache backend using unstorage

    main

    The nuxt-multi-cache module uses unstorage to manage the cache layer. By default, it uses the memory backend.

    Important: If your Nuxt application runs in multiple instances (e.g., in a load-balanced environment), you should avoid the default memory backend. Using memory cache means that purging a cache via the API will only affect the specific instance that received the request, leaving other instances with stale data. To ensure consistency across all instances, use an external cache backend like Redis.

  3. How nuxt-multi-cache configuration works

    main

    The module follows an opt-in approach. Simply installing the module does not enable any caching.

    Features are managed through a two-step process:

    1. Added: The feature is included in your application build (e.g., composables and components are available).
    2. Enabled: The feature is active and performs its actual functionality (e.g., performing the caching).

    This allows you to include composables in your code while disabling the actual caching logic during local development or debugging. You can control this via nuxt.config.ts or runtime config.

    Important: Not all configuration options can be set in nuxt.config.ts. Options that must be bundled in the server build must be passed via the server options configuration file.

  4. Best practices for useCachedAsyncData

    main

    To ensure useCachedAsyncData works correctly, follow these rules:

    1. Avoid side effects: Do not mutate external values inside the handler or the transform method. Since these functions are not executed when data is retrieved from the cache, any side effects they contain will be skipped on cache hits.
    2. Ensure unique keys: The key argument is used directly as the cache identifier. If you use the same key for two different fetch operations, the second operation will return the cached data from the first, leading to unexpected behavior.
  5. How cache tags work for invalidation

    main

    Cache tags are unique identifiers (e.g., article:235, language:de, image:313) assigned to cached items. They allow you to invalidate multiple related items across different cache layers (Component, Data, and Route) simultaneously. Instead of purging specific keys, you purge a tag, and all items associated with that tag are removed from the cache.

    By default, tag invalidation is not immediate but occurs after a configurable delay defined by api.cacheTagInvalidationDelay in the module options.

  6. How max age and expiration are calculated

    main

    The module calculates the exact expiration time using a single timestamp determined during the first cache interaction of a request, which is then stored in the event context.

    Internally, the module handles time in two ways:

    1. Seconds: Used for values representing an age (duration).
    2. Unix Timestamp (seconds): Used for specific points in time.

    When you set a max age (as seconds or a named duration), the module internally converts this into an expires property, which is a Unix timestamp representing the exact moment the item must be revalidated.

  7. Configure nuxt-multi-cache via Runtime Config

    main

    You can override certain module options at runtime using Nuxt runtime configuration (environment variables).

    Important Constraint: You can only enable features via runtime config that are already enabled in the primary module configuration. For example, if route caching is disabled in your nuxt.config, you cannot enable it using NUXT_MULTI_CACHE_ROUTE=true. Runtime config is primarily used to toggle features off or enable debug mode in specific environments.

  8. Compare nuxt-multi-cache Route Cache vs Nitro Cache

    main

    While Nuxt/Nitro provides built-in caching via routeRules and defineCachedEventHandler, nuxt-multi-cache provides different capabilities:

    FeatureNitro Cachenuxt-multi-cache
    Runtime ControlBuild-time onlyFull runtime control (e.g., disable for logged-in users)
    LifecycleEvent handler levelHooks into request and afterResponse
    ComplexityLowHigher

    When to use nuxt-multi-cache: Use it if you need to decide cacheability dynamically during a request (e.g., a 'kill switch' if a backend fails during SSR) or if you need to manage cache tags/TTL per request.

  9. Using Route Cache and CDN Headers together

    main

    The Route Cache and CDN Cache Control Headers features in nuxt-multi-cache operate independently. You can use them simultaneously to control both local server-side caching and edge/CDN caching.

    Important: Setting a max-age via useRouteCache does not automatically update the max-age of the CDN cache control header, and vice versa. You must configure the expiration/visibility for both independently if you want them to align.

  10. How Component Cache works

    main

    Component Cache allows you to cache the rendered markup of Vue components during SSR (Server-Side Rendering) or SSG (Static Site Generation).

    Core Mechanism

    When using the <RenderCacheable> wrapper, the contents of the default slot are rendered once on the server and stored as markup. Subsequent requests skip the rendering process and directly return the cached markup. On the client, the component renders normally.

    Key Requirements & Constraints

    • Single Component Slot: The slot inside <RenderCacheable> may only contain a single component. You cannot cache generic template fragments.
    • Component Naming: The component being cached must have a name.
    • Conditional Rendering: If you need to render a component conditionally, apply the v-if to the <RenderCacheable> wrapper itself, not the child component.
    • No <Teleport>: Due to Vue limitations, you cannot use <Teleport> inside a <RenderCacheable> component.
    • State Isolation: Because the component code only executes once (during the initial cache generation), you must not alter global state (e.g., Pinia, useState) from within a cached component. Any state required for rendering must be passed in via props from a parent component.
    <template>
      <div>
        <RenderCacheable>
          <Navbar />
        </RenderCacheable>
      </div>
    </template>
  11. Authorize Cache Management API requests

    main

    By default, API endpoints require authorization. You can authorize requests in three ways:

    1. Token-based (Default): Provide a token in the x-nuxt-multi-cache-token header. You can set this token via the NUXT_MULTI_CACHE_API_AUTHORIZATION_TOKEN environment variable.
    2. Custom Callback: Implement a custom check in multiCache.serverOptions.ts using defineMultiCacheOptions.
    3. Disabled: Set api.authorization to false in nuxt.config.ts. Warning: Only do this if the endpoints are not accessible publicly!
    fetch('http://localhost:3000/__nuxt_multi_cache/purge/component', {
      method: 'POST',
      headers: {
        'x-nuxt-multi-cache-token': 'hunter2',
      },
      body: JSON.stringify(['Navbar::de--chf']),
    })
  12. Implement "Stale if error" route caching

    main

    You can configure route caching to serve stale content from the cache only when the underlying route or data fetch fails (e.g., an external API is down). This allows you to maintain service availability by providing a slightly outdated response instead of an error page.

    To implement this, use the useRouteCache composable and chain the following methods on the helper object:

    • .setCacheable(): Marks the route as eligible for caching.
    • .setMaxAge(seconds): Sets the standard cache duration (how long the content is considered fresh).
    • .setStaleIfError(seconds): Sets the maximum duration to serve stale content specifically when an error occurs.

    In the example below, the route is cached for 60 seconds. If the API fails, the stale content will be served for up to 3600 seconds (1 hour).

    <script lang="ts" setup>
    const { data } = await useFetch('https://api.example.com/constantly-down')
    
    useRouteCache((helper) => {
      helper.setCacheable().setMaxAge(60).setStaleIfError(3600)
    })
    </script>