Next.js 15 Cachning: Komplett guide till fetch, unstable_cache och revalidateTag (2026)

Lär dig hur cachning verkligen fungerar i Next.js 15: fetch-cache, Data Cache, Full Route Cache och Router Cache, med kodexempel för revalidateTag och 'use cache'.

Next.js 15 Cachning: Komplett Guide (2026)

Uppdaterad: 17 juni 2026

Cachning i Next.js 15 bygger på fyra distinkta lager: fetch-cachen, Data Cache (via unstable_cache), Full Route Cache och Router Cache på klientsidan. Sedan Next.js 15 stable är fetch()-anrop okachade som standard, GET Route Handlers cachas inte längre automatiskt, och Client Router Cache har staleTime: 0 som standard. Den här guiden visar hur du explicit styr varje lager med cache: 'force-cache', revalidateTag, revalidatePath och de nya 'use cache'-direktiven, inklusive körbara kodexempel för App Router och React 19.

  • fetch() är okachad som standard i Next.js 15. Du måste explicit ange cache: 'force-cache' eller en revalidate-tagg.
  • unstable_cache ersätts gradvis av det nya 'use cache'-direktivet (canary) som markerar funktioner, sidor eller layouts som cachebara.
  • revalidateTag och revalidatePath körs från Server Actions eller Route Handlers för att invalidera specifika cacheposter on-demand.
  • Full Route Cache cachar statiskt renderade sidor på disk vid build; den invalideras vid omdistribution eller via revalidatePath.
  • Router Cache (klientsidan) har staleTime på 0 sekunder för dynamiska sidor som standard. Konfigureras via staleTimes i next.config.js.
  • Partial Prerendering (PPR) tillåter att en sida kombinerar statiskt cachat skal med dynamiska delar i samma request.

De fyra cachelagrena i Next.js 15

Innan vi rör koden behöver du en mental modell av vad som cachas och var. Next.js 15 har fyra separata cachelager som arbetar oberoende av varandra, och de allra flesta missförstånd kommer av att utvecklare blandar ihop dem. Ärligt talat har jag sett produktionsteam jaga "stale data"-buggar i veckor när problemet egentligen var att Router Cache på klienten serverade ett gammalt navigationsfragment, medan Data Cache på servern var helt korrekt.

Den officiella översikten finns i Next.js docs om caching, men här är den korta versionen som du behöver i huvudet:

LagerVarVad cachasStandard i v15Hur invalideras
Request MemoizationServer, per requestIdentiska fetch under en renderAutomatiskt vid nästa request
Data CacheServer, persistentfetch-svar och unstable_cacheAv (opt-in)revalidateTag, revalidatePath, TTL
Full Route CacheServer, build/runtimeHTML och RSC payload för statiska sidorPå för statiska routesRedeploy, revalidatePath
Router CacheKlient (browser)RSC payload per route-segment30 s för statiska, 0 s för dynamiskaNavigation, router.refresh(), staleTimes

Begreppet "cachning" i Next.js är alltså inte ett enskilt fenomen utan en kedja. När du läser felmeddelanden eller blogginlägg, identifiera först vilket lager som diskuteras. Det avgör vilken API du faktiskt behöver röra.

Så fungerar fetch-cachen i Next.js 15

Det här är den största brytande förändringen från v14: fetch()-anrop i Server Components är okachade som standard. Det är ett medvetet val från Next.js-teamet efter feedback om att den tidigare "cache by default"-modellen skapade förvirrande produktionsbuggar. Detaljerna dokumenteras i Next.js 15 release notes.

Det betyder att den här koden gör en ny request varje gång sidan renderas:

// app/products/page.tsx
// Okachad i Next.js 15, hämtas vid varje request
export default async function ProductsPage() {
  const res = await fetch('https://api.example.com/products');
  const products = await res.json();
  return <ProductList products={products} />;
}

För att aktivera cachning explicit har du tre alternativ:

// 1. Cacha för alltid (tills revalideras)
const res = await fetch(url, { cache: 'force-cache' });

// 2. Cacha med tidsbaserad revalidering (ISR-stil)
const res = await fetch(url, { next: { revalidate: 3600 } }); // 1 timme

// 3. Cacha och tagga för on-demand-invalidering
const res = await fetch(url, {
  next: { revalidate: 3600, tags: ['products'] }
});

För Route Handlers (filer i app/api/.../route.ts) cachas GET-funktioner inte heller längre per default. Vill du tillbaka till det gamla beteendet, exportera export const dynamic = 'force-static' från route-filen.

Data Cache och det nya 'use cache'-direktivet

För datakällor som inte är fetch(), till exempel direkta databasanrop via Prisma, Drizzle eller en intern SDK, använde du tidigare unstable_cache. Den fungerar fortfarande i v15 stable och är det jag rekommenderar i produktion idag:

import { unstable_cache } from 'next/cache';
import { db } from '@/lib/db';

export const getProducts = unstable_cache(
  async (categoryId: string) => {
    return db.product.findMany({ where: { categoryId } });
  },
  ['products-by-category'],          // cache key prefix
  { revalidate: 3600, tags: ['products'] }
);

I canary-versioner (Next.js 15.1+ med experimental.useCache: true) finns ett nytt direktiv som dramatiskt förenklar API:t:

// Markera en hel funktion som cachebar
async function getProducts(categoryId: string) {
  'use cache';
  return db.product.findMany({ where: { categoryId } });
}

// Eller en hel sida
export default async function Page() {
  'use cache';
  // hela komponenten cachas, inklusive nested awaits
  const data = await getStuff();
  return <Layout data={data} />;
}

När ska man välja Data Cache framför fetch-cachen?

Tumregel: om datakällan exponerar en HTTP-endpoint, använd fetch med next.tags. Om du läser direkt från en lokal process (databas, fil, intern funktion), använd unstable_cache eller 'use cache'. Båda landar i samma underliggande Data Cache och båda invalideras med revalidateTag.

Hur använder man revalidateTag och revalidatePath?

On-demand-invalidering är den absolut viktigaste skillnaden mellan Next.js cachning och en traditionell CDN. Du kan be servern att kasta specifika cacheposter mitt under en deploy. De två primära API:erna är revalidateTag(tag) och revalidatePath(path), båda från next/cache.

Det vanligaste mönstret är att kalla dem från en Server Action efter en muterande operation. Om du är ny på Server Actions, läs gärna min tidigare genomgång av Server Actions i Next.js App Router först. Den förklarar form-bindningen och säkerhetsmodellen som koden nedan förutsätter.

// app/actions/products.ts
'use server';

import { revalidateTag, revalidatePath } from 'next/cache';
import { db } from '@/lib/db';

export async function updateProduct(formData: FormData) {
  const id = formData.get('id') as string;
  const name = formData.get('name') as string;

  await db.product.update({ where: { id }, data: { name } });

  // Invalidera alla fetch-anrop som taggats 'products'
  revalidateTag('products');

  // Eller invalidera en specifik route
  revalidatePath('/products');
  revalidatePath(`/products/${id}`);
}

revalidateTag vs revalidatePath

  • revalidateTag: riktad invalidering. Du markerar fetch-anrop eller unstable_cache-anrop med tags och kan sedan invalidera bara de poster som matchar. Bäst för datadrivna invalideringar (t.ex. "alla sidor som visar produkt X").
  • revalidatePath: invaliderar Full Route Cache för en specifik path. Använd när du vet exakt vilka sidor som påverkas och vill undvika overhead av tag-lookup.

Du kan också anropa endpoints från en webhook (t.ex. ett CMS som skickar publish-events):

// app/api/revalidate/route.ts
import { revalidateTag } from 'next/cache';
import { NextResponse } from 'next/server';

export async function POST(request: Request) {
  const secret = request.headers.get('x-revalidate-secret');
  if (secret !== process.env.REVALIDATE_SECRET) {
    return NextResponse.json({ ok: false }, { status: 401 });
  }
  const { tag } = await request.json();
  revalidateTag(tag);
  return NextResponse.json({ revalidated: true });
}

Full Route Cache och statisk rendering

Full Route Cache lagrar både den renderade HTML:en och React Server Components-payloaden för sidor som Next.js klassificerar som statiska vid build. Det är det som gör en Next.js-app deployad till Vercel Edge Network blixtsnabb. Varje request serveras från CDN utan att ens nå Node-runtime.

En route blir dynamisk (och hoppar över Full Route Cache) så fort den anropar någon av följande:

  • cookies(), headers(), draftMode() från next/headers
  • searchParams som prop
  • Ett fetch() med cache: 'no-store' eller { next: { revalidate: 0 } }
  • Explicit export const dynamic = 'force-dynamic'

Att tvinga statiskt beteende kan ge enorm prestandavinst. För en produktkatalog jag optimerade i våras gick TTFB från 380 ms till under 40 ms genom att flytta cookies()-läsningen till en Client Component högre upp i trädet, så att produktsidan kunde stanna statisk.

// Tvinga statisk rendering även om Next.js misstänker dynamisk
export const dynamic = 'force-static';
export const revalidate = 3600; // ISR varje timme

Router Cache och staleTimes på klientsidan

Router Cache lever i webbläsaren och cachar RSC-payload per route-segment under en session. Det är vad som gör snabba bak-/framåtnavigeringar möjliga utan ny server-rundtur. I Next.js 15 har den fått en uttrycklig staleTimes-konfiguration:

// next.config.js
module.exports = {
  experimental: {
    staleTimes: {
      dynamic: 30,   // sekunder för dynamiska sidor (default 0)
      static: 180,   // sekunder för statiska sidor (default 300)
    },
  },
};

Standardvärdet dynamic: 0 betyder att klienten alltid hämtar färsk data när du navigerar tillbaka till en dynamisk sida. Säkert, men dyrt. Att höja det till 30 sekunder ger märkbart snabbare back-navigation i en typisk dashboard utan att riskera stale data längre än ett halvminut.

Vill du tvinga klienten att kasta sin Router Cache vid en specifik händelse, exempelvis efter en mutation som inte triggar omnavigering, anropa router.refresh():

'use client';
import { useRouter } from 'next/navigation';

export function RefreshButton() {
  const router = useRouter();
  return <button onClick={() => router.refresh()}>Uppdatera</button>;
}

Partial Prerendering: kombinera statiskt och dynamiskt

Partial Prerendering (PPR) är Next.js 15:s mest ambitiösa cachning-funktion. Tanken: en enda route levererar ett statiskt prerendrat skal direkt från CDN, och de dynamiska delarna (som kräver cookies eller per-användare-data) strömmas in via Suspense. Jag täckte grunderna i en relaterad genomgång av Next.js Middleware och Edge Runtime. PPR bygger på samma streaming-infrastruktur.

// app/dashboard/page.tsx
import { Suspense } from 'react';
import { cookies } from 'next/headers';

export const experimental_ppr = true; // aktivera PPR per route

export default function Dashboard() {
  return (
    <>
      {/* Statiskt skal, cachas vid build */}
      <Header />
      <Sidebar />

      {/* Dynamisk del, strömmas in per request */}
      <Suspense fallback={<Skeleton />}>
        <UserGreeting />
      </Suspense>
    </>
  );
}

async function UserGreeting() {
  const session = (await cookies()).get('session');
  return <p>Hej, {session?.value}!</p>;
}

För att aktivera PPR globalt, lägg till experimental: { ppr: 'incremental' } i next.config.js. 'incremental' betyder att du opt-in per route via experimental_ppr = true, vilket är säkrare än att flippa på true för hela appen.

Vanliga misstag och hur du debugger cachebeteenden

Tre debug-flaggor som sparat mig många timmar i produktion:

# Logga cache-träffar och -missar för fetch
next dev --turbopack -- --logging.fetches.fullUrl=true

# Visa vilka routes som är statiska/dynamiska efter build
next build
# Kolla utdata: ƒ (dynamic), ○ (static), ● (SSG), ◐ (PPR)

De fyra absolut vanligaste fallgropparna jag ser hos team som migrerar till Next.js 15:

  1. Förvänta sig cachning som inte längre finns. Audita alla fetch()-anrop efter uppgraderingen.
  2. Glömma tagsfetch. Utan tag kan du inte selektivt invalidera, du tvingas använda revalidatePath.
  3. Anropa revalidateTag från en Client Component. Det funkar inte. Invalidering måste ske i Server Action eller Route Handler.
  4. Blanda ihop Router Cache med Data Cache. Om revalidateTag "inte funkar", är problemet ofta att browser-cachen håller fast vid den gamla RSC-payloaden. Testa router.refresh() eller justera staleTimes.

Vanliga frågor

Varför cachas inte fetch som standard i Next.js 15?

Next.js-teamet vände på defaulten eftersom "cache by default"-modellen i v13/v14 ledde till oförutsedda produktionsbuggar där utvecklare inte insåg att de serverade stale data. Den nya modellen är explicit: du opt:ar in i cachning via cache: 'force-cache' eller next.revalidate.

Vad är skillnaden mellan revalidateTag och revalidatePath?

revalidateTag invaliderar alla cacheposter som har en specifik tagg, vilket är bra för datadrivna invalideringar. revalidatePath invaliderar Full Route Cache för en hel URL, bäst när du vet exakt vilka sidor som påverkas. Många produktionsappar använder båda i samma Server Action.

Är 'use cache'-direktivet redo för produktion?

Inte än, per juni 2026. Direktivet är experimentellt och kräver experimental.useCache: true i konfig. För produktionssystem, håll dig till unstable_cache tills 'use cache' flaggas som stable.

Hur cachar man en hel sida statiskt i App Router?

Exportera export const dynamic = 'force-static' från sidans page.tsx. Kombinera med export const revalidate = 3600 för ISR-stil revalidering. Sidan får då både Full Route Cache och Data Cache aktiverade automatiskt.

Varför ser jag fortfarande gammal data efter revalidateTag?

Server-cachen är invaliderad, men din browser kan fortfarande hålla en gammal RSC-payload i Router Cache. Anropa router.refresh() efter mutationen, eller justera experimental.staleTimes i next.config.js för att tvinga klienten att hämta färska data.

Editorial Team
Om Författaren Editorial Team

Our team of expert writers and editors.