We Can’t talk Data Fetching Without Talking About Caching in Next.js When discussing data fetching in Next.js, caching is an inseparable part of the conversation. Next.js provides powerful mechanisms for data fetching and caching to improve performance and efficiency. Caching in Next.js plays a crucial role in improving page load times, reducing server load, and enhancing user experience. Here’s why:
- Performance and Efficiency: Caching mechanisms ensure that data fetching is not only fast but also efficient, reducing redundant network requests and server load.
- User Experience: By caching data, Next.js delivers faster response times and a smoother user experience, especially for repeated or high-traffic requests.
Table of Contents
Different caching factors
The caching behavior in Next.js varies depending on factors such as
- Route status is statically or dynamically rendered
- Data is cached or uncached
- Whether a request is part of an initial visit or a subsequent navigation
We can do three different type of caching
- Static site Generation: By default fetch(‘https:// ‘, { cache: ‘force-cache’})
- Incremental site regeneration: Cache every 1 hour fetch(‘https:// ‘, { revalidate: 3600}) purge every one hours.
- Server-side rendering: No Caching fetches every times fetch(‘https:// ‘, { cache: ‘no-store})
Different methods of data fetching
Next.js provides several caching mechanisms and APIs that allow developers to configure caching behavior for individual routes and data requests. Next.js provides several methods for fetching data, tailored to different use cases
- Static Site Generation (SSG)
- Incremental Static Regeneration (ISR)
- Server-side Rendering (SSR)
- Client-side Fetching
Static Site Generation (SSG)
Static Site Generation allows you to fetch data at build time and cached by default, generating static HTML files that can be served efficiently. Next.js supports Static Site Generation (SSG), where pre-rendered HTML files can be cached and served by a global CDN, resulting in fast page loads. Optimized pages can be cached and served to end-users from multiple CDN locations. Additionally, Next.js provides client-side caching options, allowing developers to cache data on the client-side for faster subsequent requests.
fetch('https://...', { cache: 'force-cache' })
// Data is cached by default
export async function getStaticProps() {
const res = await fetch('https://api.example.com/data');
const data = await res.json();
return {
props: {
data,
},
revalidate: 3600, // Optional revalidation for ISR
};
}
function HomePage({ data }) {
return (
<div>
<h1>Data fetched at build time</h1>
<pre>{JSON.stringify(data, null, 2)}</pre>
</div>
);
}
export default HomePage;
Incremental Static Regeneration (ISR)
Next.js introduces Incremental Static Regeneration (ISR), a feature that allows developers to update static pages after they’ve been built without rebuilding the entire site. This enables dynamic content updates while still benefiting from the performance advantages of static site generation and caching.
fetch('https://...', { next: { revalidate: 3600 } });
ISR is beneficial for pages that need to be updated periodically but do not require real-time data. The code snippet fetch('https://...', { next: { revalidate: 3600 } });
is an example of using the fetch
function to make a request to an API endpoint in a Next.js application with the revalidate
option set to 3600
seconds (or 1 hour).
The revalidate
option is used in conjunction with Incremental Static Regeneration (ISR) in Next.js. ISR allows you to update static pages without rebuilding the entire site. With ISR, you can specify a revalidation interval, which determines how often the cached data should be updated.
Server-side rendering (SSR)
Next.js automatically caches the returned values of fetch requests in the Data Cache on the server. This means that the data can be fetched at build time or request time, cached, and reused on each data request. This caching behavior helps improve performance by reducing the need to refetch data on subsequent requests.
This indicates that Next.js caches the fetched data on the server, allowing it to be reused for subsequent requests, thereby improving performance.
Note: We can have server side data fetching on every request and not cached by default. This ensures that users always receive the most up-to-date data, but it can result in slower load times.
fetch('https://...', { cache: 'no-store' });
// No caching, fetches every time
Client-side Fetching
For client-side data fetching, you can use libraries like SWR, which provide caching and revalidation out of the box.
Enhanced Caching Mechanisms
Next.js provides additional caching mechanisms to optimize data fetching and improve performance:
- Request Memoization: is a technique that caches the results of API requests to avoid redundant network calls or request, enhancing performance and efficiency. In Next.js, automatically memoize fetch requests that have the same URL and options by default.
- Data Cache: Next.js stores data across user requests and deployments. By default, fetch requests are cached, and you can configure caching behavior using options like
cache
andnext.revalidate
. It is persistence, it will stay when you reload the page, as it is store in server. - Full Route Cache: Next.js caches rendered HTML and React Server Component Payload (RSC) on the server, which is useful for static routes and during revalidation 4.
These caching strategies and mechanisms in Next.js help optimize performance, reduce redundant data fetching, and enable efficient data management across different rendering methods.
Fetching data from Supabase
Here is an example of retrieving data from supbase,
const { data: students } = await supabase.from("course-2024").select();
Note: If faced an issues, once we retrieve data changing the data on supbase if it not reflected then you can have different caching approach based on your requirement. When fetching data in Next.js, caching is critical for optimal performance. By default, Next.js caches generated HTML, which can lead to stale data when server-side data sources such as Supabase change.
Strategies for dealing with stale data:
- Clear the cache: Delete the .next folder to force Next.js to rebuild pages and fetch the latest data. This may slow down initial loads as the cache is rebuilt.
- Implement data revalidation: Use the revalidate property to specify how often Next.js should refresh data. For example, revalidate: 60 will refresh data every 60 seconds, balancing performance and freshness.
- Client-side caching: Use libraries such as SWR (Stale-While-Revalidate) for client-side caching and background data revalidation.
This keeps data up to date without requiring a full page refresh. Choose your approach based on the needs of your application, taking into account the frequency of data changes, the importance of real-time updates, and the trade-off between performance and data freshness. For Supbase we can’t directly add caching related on fetch as supbase indirectly used fetch. So we can add export const revalidate = 0; on page or attribute in nextjs as follow.
import { createClient } from "@/supabase/client";
export const revalidate = 0;
export default async function Home() {
const supabase = createClient();
const { data: students } = await supabase.from("course-2024").select();
....