Skip to content
Dashboard

Vercel Data Cache: A progressive cache, integrated with Next.js

Framework-defined, global caching infrastructure with zero configuration.

Link to headingWhat is Incremental Static Regeneration (ISR)?

Link to headingThe good, the bad, and the ugly of ISR

pages/products/[id].js
export async function getStaticProps() {
let product = await getProduct()
return {
props: { product },
// Next.js will attempt to re-generate the page:
// - When a request comes in
// - At most once every 10 seconds
revalidate: 10, // In seconds
}
}
// Generates `/products/1` and `/products/2`
export async function getStaticPaths() {
// The developer has full flexibility to control
// what pages are generated during the build or on-demand
// For example, you could only generate the top products
// const topProducts = await getTopProducts()
return {
paths: [{ params: { id: '1' } }, { params: { id: '2' } }],
fallback: 'blocking', // generate new product pages on-demand
}
}

Using ISR inside of the Next.js pages directory.

pages/products/[id].js
export async function getStaticProps() {
let product = await getProduct()
return {
props: { product },
// `revalidate` is no longer needed, content is only updated
// when programmatically invalidated through the API
// revalidate: 10
}
}

Using revalidate is not necessary when programmatically updating content.

pages/api/revalidate.js
export default async function handler(req, res) {
// ...
await res.revalidate('/products/1');
// ...
}

An API Route that uses On-Demand ISR.

Link to headingThe new App Router, designed for incremental adoption

Link to headingImproved data fetching with React Server Components

app/page.jsx
export default async function Page() {
let notes = await db.query('select * from notes');
return (
<ul>
{notes.map((note) => (
<li key={note.id}>{note.body}</li>
))}
</ul>
);
}

With React Server Components, you can fetch data directly inside of your components.

app/page.js
export default async function Page() {
const [staticData, dynamicData, revalidatedData] = await Promise.all([
// Cached until manually invalidated
fetch(`https://...`),
// Refetched on every request
fetch(`https://...`, { cache: 'no-store' }),
// Cached with a lifetime of 10 seconds
fetch(`https://...`, { next: { revalidate: 10 } }),
]);
return <div>...</div>;
}

The data fetching API inside of the App Router has been simplified.

Link to headingThe Next Generation of ISR: Next.js Cache

app/page.tsx
async function Tweet({ id }) {
// Tweets are static unless programmatically revalidated
let tweet = await fetch(`https://.../${id}`).then(res => res.json());
return (
<div>
<p>{tweet.author}</p>
</div>
);
}
async function Categories() {
// Fetch the latest categories at most every 60 seconds
let trendingCategories = await fetch('https://...', {
next: { revalidate: 60 },
}.then(res => res.json());
return (
<ul>
{trendingCategories.map((category) => (
<li key={category.id}>{category.name}</li>
))}
</ul>
);
}

You can revalidate a single fetch at most every 60 seconds.

Link to headingHow the Next.js Cache Works

Link to headingNext.js Cache with the Vercel Data Cache

Link to headingSelf-Hosted Next.js

Link to headingRevalidating components with cache tags

revalidatePath(`/posts/[slug]`);
revalidateTag(`post-${id}`);

An upcoming API for allowing revalidation of content by tag.

fetch(url, { next: { tags: [...] } });

Cache tags can be added to the fetch request.

Link to headingGetting started with the Next.js Cache