Cache Components

Back

Loading concept...

🏪 The Magic Refrigerator: Understanding Next.js Cache Components

Imagine you have a magic refrigerator that remembers every snack you ever wanted…


🎯 What’s This All About?

Think of a cache like a super-smart refrigerator in a restaurant kitchen. Instead of cooking the same dish from scratch every time someone orders it, the chef saves ready-made portions. When the next customer orders the same thing — boom! — instant delivery!

In Next.js, Cache Components work the same way. They save the results of expensive operations (like fetching data from a faraway server) so your app doesn’t have to repeat the work.

The Big Picture:

Without Cache:        With Cache:
────────────────      ────────────────
User asks → Cook      User asks → Check fridge
Wait 5 seconds        Already there? → Instant!
Get food              Not there? → Cook once, save
                      Next time → Instant!

📚 The Six Magic Spells

We’re learning six special tools (like magic spells) for our refrigerator:

  1. use cache Directive — The magic wand that turns any function into a cacheable one
  2. Cache Key Generation — How the fridge knows which container holds which food
  3. cacheLife Configuration — How long food stays fresh
  4. cacheTag Function — Labels on containers so we can find and throw away specific items
  5. Cacheable Functions — Which recipes can be stored
  6. Cache Scope — Where the fridge is located (kitchen vs. restaurant-wide)

1️⃣ The use cache Directive

What Is It?

Think of "use cache" as saying “Hey fridge, save this for later!”

It’s a special instruction you put at the top of a function. Once you add it, Next.js automatically saves the result.

Simple Example

// Without cache - cooks every time
async function getWeather() {
  // This runs EVERY time someone asks
  const weather = await fetch('/api/weather');
  return weather;
}

// With cache - cooks once, serves many
async function getWeather() {
  "use cache";  // ← Magic words!

  // This runs ONCE, then serves from fridge
  const weather = await fetch('/api/weather');
  return weather;
}

Real Life Example

Imagine 100 users visit your weather page in one minute:

Without Cache With Cache
100 API calls 1 API call
Server exhausted 😓 Server relaxed 😎
Users wait Instant for 99 users

Where Can You Use It?

// ✅ In a function
async function getPosts() {
  "use cache";
  return fetchPosts();
}

// ✅ At the top of a file (caches ALL functions)
"use cache";

export async function getUsers() { ... }
export async function getPosts() { ... }

2️⃣ Cache Key Generation

What Is It?

The cache key is like a label on a container in your fridge. It tells the fridge exactly what’s inside.

If you ask for “chocolate cake”, the fridge looks for a container labeled “chocolate cake” — not “vanilla cake”!

How Next.js Creates Keys

Next.js automatically creates labels using:

  • The function name
  • The arguments you pass
graph TD A["getUser#40;5#41;"] -->|Creates key| B["getUser-5"] C["getUser#40;10#41;"] -->|Creates key| D["getUser-10"] E["Different keys = Different containers!"]

Example: Same Function, Different Keys

async function getUser(userId: number) {
  "use cache";
  return fetch(`/api/users/${userId}`);
}

// These create DIFFERENT cache entries:
getUser(1);  // Key: getUser-1 → Fetches user 1
getUser(2);  // Key: getUser-2 → Fetches user 2
getUser(1);  // Key: getUser-1 → Returns cached!

What Gets Included in the Key?

Included ✅ Not Included ❌
Function arguments Date/time of call
Serializable values Random numbers inside
Strings, numbers, objects External variables

⚠️ Warning: Non-Serializable Values

// ❌ BAD - Objects with methods can't be cached
getUser({ id: 1, getName: () => "John" });

// ✅ GOOD - Plain data only
getUser({ id: 1, name: "John" });

3️⃣ The cacheLife Configuration

What Is It?

Food in your fridge doesn’t last forever, right? Milk expires, leftovers go bad. cacheLife tells Next.js how long to keep cached data fresh.

The Three Time Settings

graph TD A["cacheLife has 3 timers"] --> B["stale: When it's 'old' but ok"] A --> C["revalidate: When to check for fresh"] A --> D["expire: When to throw away"]

Built-in Presets

Next.js gives you ready-made settings like choosing fridge temperatures:

import { cacheLife } from 'next/cache';

async function getNews() {
  "use cache";
  cacheLife("minutes");  // Fresh for a few minutes
  return fetchNews();
}

async function getAboutPage() {
  "use cache";
  cacheLife("hours");    // Fresh for hours
  return fetchAbout();
}
Preset Stale Revalidate Expire
"seconds" Instant 1 second 1 minute
"minutes" 5 min 1 minute 1 hour
"hours" 5 min 1 hour 1 day
"days" 5 min 1 day 1 week
"weeks" 5 min 1 week 1 month
"max" 5 min 1 month Forever

Custom Configuration

Want your own expiry times? Define them in next.config.js:

// next.config.js
module.exports = {
  experimental: {
    cacheLife: {
      "blog-posts": {
        stale: 300,      // 5 minutes
        revalidate: 600, // 10 minutes
        expire: 3600     // 1 hour
      }
    }
  }
};

Then use it:

async function getBlogPosts() {
  "use cache";
  cacheLife("blog-posts");  // Your custom setting!
  return fetchPosts();
}

4️⃣ The cacheTag Function

What Is It?

Imagine you have 50 containers in your fridge. How do you find and throw away all the “salad” containers at once? Tags!

cacheTag lets you add labels like sticky notes. Later, you can tell the fridge: “Throw away everything tagged ‘user-123’”.

How It Works

import { cacheTag } from 'next/cache';

async function getUserProfile(userId: string) {
  "use cache";
  cacheTag(`user-${userId}`);  // Tag this cache entry
  return fetchUser(userId);
}

async function getUserPosts(userId: string) {
  "use cache";
  cacheTag(`user-${userId}`);  // Same tag = grouped together
  return fetchPosts(userId);
}

Invalidating by Tag

When user 123 updates their profile, clear all their cached data:

import { revalidateTag } from 'next/cache';

async function updateUser(userId: string, data: any) {
  // Update in database
  await saveUser(userId, data);

  // Clear ALL caches with this tag
  revalidateTag(`user-${userId}`);
  // Now profile AND posts will be re-fetched!
}

Multiple Tags

One container can have many sticky notes:

async function getDashboardData(userId: string) {
  "use cache";
  cacheTag("dashboard");           // Tag 1
  cacheTag(`user-${userId}`);      // Tag 2
  cacheTag("analytics");           // Tag 3

  return fetchDashboard(userId);
}

// Now you can clear by ANY tag:
revalidateTag("dashboard");  // Clears ALL dashboards
revalidateTag("user-5");     // Clears just user 5's data

5️⃣ Cacheable Functions

What Is It?

Not every recipe can go in the fridge! Ice cream? Yes. Hot soup? Not a great idea.

Cacheable functions are functions that can safely be cached.

Rules for Cacheable Functions

graph TD A["Can This Be Cached?"] --> B{"Is output serializable?"} B -->|Yes| C{"Same input = same output?"} C -->|Yes| D["✅ CACHEABLE!"] B -->|No| E["❌ NOT cacheable"] C -->|No| E

✅ Good Candidates

// ✅ Fetching data - same ID always returns same user
async function getUser(id: number) {
  "use cache";
  return db.users.find(id);
}

// ✅ Calculations - same numbers, same result
async function calculateTax(amount: number) {
  "use cache";
  return amount * 0.1;
}

// ✅ Static content - rarely changes
async function getConfig() {
  "use cache";
  return fetchAppConfig();
}

❌ Bad Candidates

// ❌ Random values - different every time!
async function getRandomQuote() {
  "use cache";  // BAD IDEA!
  return quotes[Math.random() * quotes.length];
}

// ❌ Time-dependent - changes every second
async function getCurrentTime() {
  "use cache";  // Will return stale time!
  return new Date();
}

// ❌ User session data - changes with each user
async function getCurrentUserCart() {
  "use cache";  // Wrong user might see wrong cart!
  return getSessionCart();
}

The Golden Rule

If calling the function twice with the same input should give the same output, it’s cacheable!


6️⃣ Cache Scope

What Is It?

Where is your refrigerator? In your apartment (private) or in the building lobby (shared)?

Cache scope determines who shares the cached data.

Two Main Scopes

graph TD A["Cache Scope"] --> B["Request Scope"] A --> C["Build/Server Scope"] B --> D["Per-user, per-request<br/>Like a personal lunchbox"] C --> E["Shared across all users<br/>Like a restaurant fridge"]

Request-Level Scope

Used for data that might be different per user or per request:

// This cache lives only during one request
import { cache } from 'react';

const getUser = cache(async (id: string) => {
  return fetchUser(id);
});

// Within ONE request:
getUser("abc");  // Fetches
getUser("abc");  // Returns cached (same request)

// In NEXT request:
getUser("abc");  // Fetches again (new request)

Server/Build-Level Scope (Default with use cache)

Shared across ALL users and requests:

async function getPopularProducts() {
  "use cache";
  cacheLife("hours");
  return fetchPopularProducts();
}

// User A visits: Fetches and caches
// User B visits: Gets cached version!
// User C visits: Gets cached version!
// 1 hour later: Someone fetches fresh data

When to Use Which?

Scope Use For Example
Request User-specific data Shopping cart
Server Public data Blog posts, products
Build Static data Site config, footer

🎮 Let’s Put It All Together!

Here’s a real-world example using ALL six concepts:

// page.tsx
import { cacheTag, cacheLife } from 'next/cache';

// 1️⃣ use cache - Enable caching
// 2️⃣ cacheLife - Set expiration
// 3️⃣ cacheTag - Add labels
// 4️⃣ Cache Key - userId makes each user's data unique
// 5️⃣ Cacheable - Returns serializable data
// 6️⃣ Scope - Shared server cache

async function getUserDashboard(userId: string) {
  "use cache";                    // 1️⃣ Magic words

  cacheLife("minutes");           // 2️⃣ Keep for minutes
  cacheTag(`user-${userId}`);     // 3️⃣ Tag for easy clearing
  cacheTag("dashboard");          // 3️⃣ Another tag

  // 4️⃣ userId becomes part of cache key
  // 5️⃣ Returns plain JSON (cacheable!)
  const data = await fetchDashboard(userId);

  // 6️⃣ This runs on server, shared with same userId
  return data;
}

// Clear cache when user updates profile
async function updateProfile(userId: string) {
  await saveProfile(userId);
  revalidateTag(`user-${userId}`);  // Clears dashboard too!
}

🧠 Quick Memory Tricks

Concept Remember As
use cache “Save this recipe”
Cache Key “Container label”
cacheLife “Expiration date”
cacheTag “Sticky note”
Cacheable “Can it be frozen?”
Cache Scope “Personal vs. shared fridge”

🚀 You Did It!

You now understand the six magic spells of Next.js caching:

  1. use cache turns functions into smart, cached versions
  2. Cache Keys ensure different inputs get different cached results
  3. cacheLife controls how long data stays fresh
  4. cacheTag lets you group and invalidate related caches
  5. Cacheable Functions must have predictable, serializable outputs
  6. Cache Scope determines if cache is personal or shared

Your app will now be faster than ever! 🎉


Remember: Caching is like having a super-smart refrigerator. Use it wisely, and your users will enjoy lightning-fast experiences!

Loading story...

Story - Premium Content

Please sign in to view this story and start learning.

Upgrade to Premium to unlock full access to all stories.

Stay Tuned!

Story is coming soon.

Story Preview

Story - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.