Skip to content

Caching Strategies

Three caches sit between a component and Kirby, each with a different lifetime.

Overview

Cache TypeLocationScopePersistenceBest For
PayloadNuxt payloadPer sessionUntil page reloadFrequent queries
Server-sideNitro cacheCross-requestConfigurable TTLExpensive operations
Build-timeStatic filesPermanentUntil rebuildStable content

Payload Caching

useKql and useKirbyData derive their async data key from the request, so two call sites asking for the same thing share one entry and one round trip:

ts
// First call - fetches from Kirby
const { data: firstCall } = await useKql({
  query: 'site',
  select: ['title']
})

// Second call - resolves from the entry the first one filled
const { data: secondCall } = await useKql({
  query: 'site',
  select: ['title']
})

The key covers:

  • Query content (for KQL)
  • Path, method, query parameters and body (for direct API)
  • Language setting
  • Request headers
  • forwardCookies

$kql and $kirby have no async data around them, so they keep a payload cache of their own. Set their payloadCache option to false for real-time data that changes frequently:

ts
const site = await $kql(query, {
  payloadCache: false
})

The option governs repeated calls within one environment, not the handover between them. A response fetched during SSR always travels to the client in the payload, and the hydrating call reads it there – otherwise every query would cost a second round trip in the browser for no gain. Caching stops after that: the next call sends the query again.

Custom Cache Management

refresh sends the query again and replaces the stored result, clear empties it without fetching:

ts
const { data, refresh, clear } = await useKql(query)

Server-Side Caching

The proxy can cache responses through Nitro's cache API. They live in memory by default; any Nitro storage mountpoint persists them across restarts.

TIP

All built-in storage mountpoints can be found in the unstorage documentation.

Concurrent requests for the same query then cost one round trip to Kirby rather than one each.

You can enable server-side caching by setting the server.cache module option to true. You can also set a custom expiration time in seconds by setting the server.maxAge option:

ts
// `nuxt.config.ts`
export default defineNuxtConfig({
  modules: ['nuxt-kirby'],

  kirby: {
    server: {
      // Enable server-side caching
      // @default false
      cache: true,
      // Number of seconds to cache the data response
      // @default 1
      maxAge: 60 * 60 * 24 * 7, // 7 days
    }
  }
})

The module will use the cache storage mountpoint by default. However, for better control over your cache, a custom storage mountpoint is best suited in production environments. For development purposes, you can use the built-in fs storage mountpoint.

INFO

For example, if you are deploying to Cloudflare, the Cloudflare KV storage would be a good choice.

To define a custom storage mountpoint, set the server.storage option to the name of your custom mountpoint. Then, define the storage mountpoint in the nitro.storage section of your nuxt.config.ts:

ts
// `nuxt.config.ts`
export default defineNuxtConfig({
  modules: ['nuxt-kirby'],

  kirby: {
    server: {
      // Enable server-side caching
      // @default false
      cache: true,
      // Storage mountpoint to use for caching
      // @default 'cache'
      storage: 'kirby',
      // Number of seconds to cache the data response
      // @default 1
      maxAge: 60 * 60 * 24 * 7, // 7 days
    }
  },

  nitro: {
    storage: {
      kirby: {
        // https://unstorage.unjs.io/drivers/cloudflare
        driver: 'cloudflareKVBinding',
        // Make sure to link the namespace in your worker settings
        binding: 'KV_BINDING'
      }
    },
    // Make sure to define a fallback storage mountpoint for local development,
    // since the Cloudflare KV binding is not available locally
    devStorage: {
      kirby: {
        driver: 'fs',
        base: '.data',
      },
    },
  }
})

In the example above, the kirby storage mountpoint will use the Cloudflare KV driver for production and the fs driver for local development.

Released under the MIT License.