Buy Pro
Docs
Caching

Caching

Optimize app performance and reduce server load effectively.

Caching improves performance by temporarily storing data, reducing the need for repeated requests or computations.

Disk Cache

Disk caching stores data on the server, making it durable across restarts. The disk cache is shared, means once a user of the organizations hits for example the /contacts route, the data is cached for the whole organization.

unstable_cache enables disk-based caching to minimize redundant computations and speed up response times. The caching functionality consinsts of three parts:

  • fetchFunction: The function that retrieves data.
  • keyParts: Unique identifiers for the cache entry, preventing data conflicts.
  • options: Extra settings like tags to group related cache entries.
import { unstable_cache } from 'next/cache';
 
async function getContacts(params: GetContactsParams): Promise<ContactDto[]> {
  return unstable_cache(
    fetchContactsFromDatabase,
    // Use keyParts to create a new cache entry that depends on the params
    [
      'organizations',
      session.user.organizationId,
      'contacts',
      params.pageIndex,
      params.pageSize,
      params.searchQuery
    ],
    {
      // Use tags to 'group' data that belongs together
      tags: [`organizations:${session.user.organizationId}:contacts`]
    }
  );
}

For a type-safe access you can use the Caching helper:

import { unstable_cache } from 'next/cache';
import { Caching, OrganizationCacheKey } from '@/data/caching';
 
async function getContacts(params: GetContactsParams): Promise<ContactDto[]> {
  return unstable_cache(
    fetchContactsFromDatabase,
    Caching.createOrganizationKeyParts(
      OrganizationCacheKey.Contacts,
      session.user.organizationId,
      params.pageIndex,
      params.pageSize,
      params.searchQuery
    ),
    {
      tags: [
        Caching.createOrganizationTag(
          OrganizationCacheKey.Contacts,
          session.user.organizationId
        )
      ]
    }
  );
}

After a mutation, like adding a new contact, you can revalidate a cache by calling it's tag:

import { revalidateTag } from 'next/cache';
 
revalidateTag(
  Caching.createOrganizationTag(
    OrganizationCacheKey.Contacts,
    session.user.organizationId
  )
);

Deduplication

Deduplication prevents redundant operations for identical requests by reusing cached results instead.

React.cache is an in-memory cache to deduplicate function calls within the same session. When called with the same parameters, React.cache avoids re-fetching data, improving efficiency.

One common use-case is the deduplication of the auth method from next-auth.

import { cache } from 'react';
 
export const dedupedAuth = cache(auth);