Guide

Cache

Nitro provides a caching system built on top of the storage layer.


Cached event handlers

To cache an event handler, you've just to use the defineCachedEventHandler method.

It works like defineEventHandler but with an additional second options parameter.

routes/cached.ts
// Cache an API handler
export default defineCachedEventHandler((event) => {
  // My event handler
}, { maxAge: 60 * 60 /* 1 hour */ });

With this example, the response will be cached for 1 hour and a stale value will be sent to the client while the cache is being updated in the background. If you want to immediately return the updated response set swr: false.

All incoming request headers are dropped when handling cached responses. If you define the varies option, only the specified headers will be considered when caching and serving the responses.

See the options section for more details about the available options.

You can also use the cachedEventHandler method as alias of defineCachedEventHandler.

Cached functions

You can also cache a function using the defineCachedFunction function. This is useful to cache the result of a function that is not an event handler but a part of it and reuse it in multiple handlers.

For example, you could want to cache for 1 hour the result of an API call:

export const cachedGHStars = defineCachedFunction(async (repo: string) => {
  const data: any = await $fetch(`https://api.github.com/repos/${repo}`)

  return data.stargazers_count
}, {
  maxAge: 60 * 60,
  name: 'ghStars',
  getKey: (repo: string) => repo
})

The stars will be cached in development inside .nitro/cache/functions/ghStars/<owner>/<repo>.json with value being the number of stars.

{"expires":1677851092249,"value":43991,"mtime":1677847492540,"integrity":"ZUHcsxCWEH"}
You can also use the cachedFunction method as alias of defineCachedFunction.

Edge workers

In a edge workers, the instance is destroyed after each request. Nitro automatically uses event.waitUntil to keep the instance alive while the cache is being updated while the response is sent to the client.

To make sure your cached functions are working as expected in a edge workers, you should always give the event as first argument to the function with defineCachedFunction.

import type { H3Event } from 'h3'

export const cachedGHStars = defineCachedFunction(async (event: H3Event, repo: string) => {
  const data: any = await $fetch(`https://api.github.com/repos/${repo}`)

  return data.stargazers_count
}, {
  maxAge: 60 * 60,
  name: 'ghStars',
  getKey: (event: H3Event, repo: string) => repo
})

This way, the function will be able to keep the instance alive while the cache is being updated without slowing down the response to the client.

Caching route rules

This feature enables you to add caching routes based on a glob pattern directly in the main configuration file. This is especially useful to have a global cache strategy for a part of your application.

Cache all the blog routes for 1 hour with stale-while-revalidate behavior:

export default defineNitroConfig({
  routeRules: {
    "/blog/**": { cache: { maxAge: 60 * 60 } },
  },
});

If we want to use a custom storage mount point, we can use the base option.

export default defineNitroConfig({
  storage: {
    redis: {
      driver: "redis",
      url: "redis://localhost:6379",
    },
  },
  routeRules: {
    "/blog/**": { cache: { maxAge: 60 * 60, base: "redis" } },
  },
});

Customize cache storage

Nitro stores the data in the cache: mount point.

To overwrite the production storage, set the cache mount point using the storage option:

export default defineNitroConfig({
  storage: {
    cache: {
      driver: 'redis',
      /* redis connector options */
    }
  }
})

In development, you can also overwrite the cache mount point using the devStorage option:

export default defineNitroConfig({
  devStorage: {
    cache: {
      driver: 'redis',
      /* redis connector options */
    }
  }
})

Options

The cachedEventHandler and cachedFunction functions accept the following options:

base
string

Name of the storage mountpoint to use for caching.
Default to cache.

name
string

Guessed from function name if not provided and fallback to '_' otherwise.

group
string

Default to 'nitro/handlers' for handlers and 'nitro/functions' for functions.

getKey()
(...args) => string

A function that accepts the same arguments of the function and returns a cache key (String).
If not provided, a built-in hash function will be used that will generate a key based on the function arguments.

integrity
string

A value that invalidates the cache when changed.
By default, it is computed from function code, used in development to invalidate the cache when the function code changes.

maxAge
number

Maximum age that cache is valid in seconds.
Default to 1 (second).

staleMaxAge
number

Maximum age that a stale cache is valid in seconds. If set to -1 a stale value will still be sent to the client, while updating the cache in the background.
Default to 0 (disabled).

swr
boolean

Enable stale-while-revalidate behavior to serve a stale cached response while asynchronously revalidating it.
Default to true.

shouldInvalidateCache()
(..args) => boolean

A function that returns a boolean to invalidate the current cache and create a new one.

shouldBypassCache()
(..args) => boolean

A function that returns a boolean to bypass the current cache without invalidating the existing entry.

varies
string[]

An array of request headers to be considered for the cache, learn more. If utilizing in a multi-tenant environment, you may want to pass ['host', 'x-forwarded-host'] to ensure these headers are not discarded and that the cache is unique per tenant.

Cache keys and invalidation

When using the defineCachedFunction or defineCachedEventHandler functions, the cache key is generated using the following pattern:

`${options.group}:${options.name}:${options.getKey(...args)}.json`

For example, the following function:

const getAccessToken = defineCachedFunction(() => {
  return String(Date.now())
}, {
  maxAge: 10,
  name: 'getAccessToken',
  getKey: () => 'default'
})

Will generate the following cache key:

nitro:functions:getAccessToken:default.json

You can invalidate the cached function entry with:

await useStorage('cache').removeItem('nitro:functions:getAccessToken:default.json')