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);