In the server rooms of Metropolis Quantum 2150, where every millisecond counts, you will learn about the revolutionary caching API introduced in Next.js 15. The
use cache directive replaces the deprecated unstable_cache and brings a much more intuitive way to manage the cache.use cache is a new directive (similar to use server or use client) that marks functions or entire files as cacheable. Next.js automatically manages the cache lifecycle and revalidation.To use
use cache, you first need to enable the experimental dynamicIO flag:1// next.config.js
2module.exports = {
3 experimental: {
4 dynamicIO: true,
5 },
6};1// app/lib/data.ts
2async function getProducts() {
3 'use cache';
4
5 const response = await fetch('https://api.quantum-store.com/products');
6 return response.json();
7}1// app/lib/cached-data.ts
2'use cache';
3
4export async function getUsers() {
5 const response = await fetch('https://api.quantum-store.com/users');
6 return response.json();
7}
8
9export async function getOrders() {
10 const response = await fetch('https://api.quantum-store.com/orders');
11 return response.json();
12}The
cacheLife function lets you precisely define how long data should be stored in the cache.Next.js ships with built-in time profiles:
1import { cacheLife } from 'next/cache';
2
3async function getNews() {
4 'use cache';
5 cacheLife('minutes'); // cache for a few minutes
6
7 return fetch('https://api.quantum-news.com/latest').then(r => r.json());
8}
9
10async function getStaticContent() {
11 'use cache';
12 cacheLife('days'); // cache for days
13
14 return fetch('https://api.quantum-cms.com/static').then(r => r.json());
15}
16
17async function getRealTimeData() {
18 'use cache';
19 cacheLife('seconds'); // cache for seconds
20
21 return fetch('https://api.quantum-sensors.com/data').then(r => r.json());
22}| Profile | stale | revalidate | expire | Description | |--------|-------|------------|--------|------| |
seconds | - | 1s | 60s | For rapidly changing data |
| minutes | 5min | 1min | 1h | For data updated every few minutes |
| hours | 5min | 1h | 1d | For hourly data |
| days | 5min | 1d | 1w | For rarely changing data |
| weeks | 5min | 1w | 30d | For near-static data |
| max | 5min | 30d | 1y | Maximum cache duration |You can define your own profiles in
next.config.js:1// next.config.js
2module.exports = {
3 experimental: {
4 dynamicIO: true,
5 cacheLife: {
6 quantumFast: {
7 stale: 10, // seconds - time when data is "fresh"
8 revalidate: 30, // seconds - time after which to revalidate in background
9 expire: 300, // seconds - maximum lifetime
10 },
11 quantumProducts: {
12 stale: 60,
13 revalidate: 300,
14 expire: 3600,
15 },
16 },
17 },
18};Using a custom profile:
1import { cacheLife } from 'next/cache';
2
3async function getQuantumProducts() {
4 'use cache';
5 cacheLife('quantumProducts');
6
7 return fetch('https://api.quantum-store.com/products').then(r => r.json());
8}You can also define the configuration directly:
1import { cacheLife } from 'next/cache';
2
3async function getCriticalData() {
4 'use cache';
5 cacheLife({
6 stale: 5,
7 revalidate: 15,
8 expire: 60,
9 });
10
11 return fetch('https://api.quantum-critical.com/data').then(r => r.json());
12}cacheTag lets you label the cache with tags that can later be used for selective revalidation.1import { cacheTag, cacheLife } from 'next/cache';
2
3async function getProduct(id: string) {
4 'use cache';
5 cacheTag(`product-${id}`);
6 cacheLife('hours');
7
8 return fetch(`https://api.quantum-store.com/products/${id}`).then(r => r.json());
9}
10
11async function getCategory(slug: string) {
12 'use cache';
13 cacheTag('categories', `category-${slug}`);
14 cacheLife('days');
15
16 return fetch(`https://api.quantum-store.com/categories/${slug}`).then(r => r.json());
17}1// app/actions/revalidate.ts
2'use server';
3
4import { revalidateTag } from 'next/cache';
5
6export async function updateProduct(id: string, data: ProductData) {
7 // Update product in the database
8 await db.products.update(id, data);
9
10 // Revalidate cache for this product
11 revalidateTag(`product-${id}`);
12}
13
14export async function refreshAllCategories() {
15 // Revalidate all categories at once
16 revalidateTag('categories');
17}1// app/lib/dashboard-data.ts
2import { cacheTag, cacheLife } from 'next/cache';
3
4// Product data - cache for hours, tagged
5export async function getDashboardProducts() {
6 'use cache';
7 cacheTag('dashboard', 'products');
8 cacheLife('hours');
9
10 const response = await fetch('https://api.quantum-store.com/dashboard/products');
11 return response.json();
12}
13
14// Sales stats - cache for minutes (frequent updates)
15export async function getSalesStats() {
16 'use cache';
17 cacheTag('dashboard', 'sales');
18 cacheLife('minutes');
19
20 const response = await fetch('https://api.quantum-store.com/dashboard/sales');
21 return response.json();
22}
23
24// User data - cache for days
25export async function getUserStats() {
26 'use cache';
27 cacheTag('dashboard', 'users');
28 cacheLife('days');
29
30 const response = await fetch('https://api.quantum-store.com/dashboard/users');
31 return response.json();
32}1// app/actions/dashboard-actions.ts
2'use server';
3
4import { revalidateTag } from 'next/cache';
5
6export async function refreshDashboard() {
7 // Revalidate the entire dashboard
8 revalidateTag('dashboard');
9}
10
11export async function refreshSalesOnly() {
12 // Revalidate only sales
13 revalidateTag('sales');
14}1// app/dashboard/page.tsx
2import { getDashboardProducts, getSalesStats, getUserStats } from '@/lib/dashboard-data';
3import { refreshDashboard, refreshSalesOnly } from '@/actions/dashboard-actions';
4
5export default async function DashboardPage() {
6 const [products, sales, users] = await Promise.all([
7 getDashboardProducts(),
8 getSalesStats(),
9 getUserStats(),
10 ]);
11
12 return (
13 <div className="quantum-dashboard">
14 <header className="flex justify-between items-center">
15 <h1>Dashboard Quantum Store</h1>
16 <div className="flex gap-2">
17 <form action={refreshSalesOnly}>
18 <button type="submit">Refresh sales</button>
19 </form>
20 <form action={refreshDashboard}>
21 <button type="submit">Refresh all</button>
22 </form>
23 </div>
24 </header>
25
26 <div className="grid grid-cols-3 gap-6">
27 <ProductsWidget data={products} />
28 <SalesWidget data={sales} />
29 <UsersWidget data={users} />
30 </div>
31 </div>
32 );
33}| Feature | use cache | unstable_cache | |-------|-----------|----------------| | Syntax | Directive | Wrapper function | | Time configuration | cacheLife() | revalidate option | | Tagging | cacheTag() | tags option | | Scope | Function or file | Function only | | Status | Stable (Next.js 15) | Deprecated |
Before (old way):
1import { unstable_cache } from 'next/cache';
2
3const getCachedProducts = unstable_cache(
4 async () => {
5 return fetch('https://api.com/products').then(r => r.json());
6 },
7 ['products'],
8 { revalidate: 3600, tags: ['products'] }
9);After (new way):
1import { cacheTag, cacheLife } from 'next/cache';
2
3async function getProducts() {
4 'use cache';
5 cacheTag('products');
6 cacheLife('hours');
7
8 return fetch('https://api.com/products').then(r => r.json());
9}The
use cache directive in Next.js 15 introduces:cacheLife with profiles or custom configurationscacheTag for precise refreshIn Metropolis Quantum 2150, where data flows at the speed of light, proper caching is the difference between a lightning-fast application and one that barely keeps up. Master
use cache and your Next.js applications will run at top speed!