Incremental Static Regeneration (ISR)

Beispiele

Next.js ermöglicht es Ihnen, statische Seiten nach dem Build Ihrer Website zu erstellen oder zu aktualisieren. Incremental Static Regeneration (ISR) erlaubt die Verwendung von statischer Generierung auf Seitenbasis, ohne die gesamte Website neu bauen zu müssen. Mit ISR können Sie die Vorteile statischer Seiten beibehalten und gleichzeitig auf Millionen von Seiten skalieren.

Wichtig: Die edge-Runtime ist derzeit nicht mit ISR kompatibel, obwohl Sie stale-while-revalidate nutzen können, indem Sie den cache-control-Header manuell setzen.

Um ISR zu verwenden, fügen Sie die revalidate-Prop zu getStaticProps hinzu:

function Blog({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  )
}

// Diese Funktion wird beim Build auf der Serverseite aufgerufen.
// Sie kann erneut aufgerufen werden, in einer serverlosen Funktion,
// wenn die Revalidierung aktiviert ist und eine neue Anfrage eingeht
export async function getStaticProps() {
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  return {
    props: {
      posts,
    },
    // Next.js wird versuchen, die Seite neu zu generieren:
    // - Bei einer eingehenden Anfrage
    // - Höchstens einmal alle 10 Sekunden
    revalidate: 10, // In Sekunden
  }
}

// Diese Funktion wird beim Build auf der Serverseite aufgerufen.
// Sie kann erneut aufgerufen werden, in einer serverlosen Funktion,
// wenn der Pfad noch nicht generiert wurde.
export async function getStaticPaths() {
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  // Pfade basierend auf den Posts für das Pre-Rendering ermitteln
  const paths = posts.map((post) => ({
    params: { id: post.id },
  }))

  // Nur diese Pfade werden beim Build pre-rendered.
  // { fallback: 'blocking' } rendert Seiten bei Bedarf
  // serverseitig, wenn der Pfad nicht existiert.
  return { paths, fallback: 'blocking' }
}

export default Blog

Wenn eine Anfrage an eine Seite gestellt wird, die beim Build pre-rendered wurde, wird zunächst die zwischengespeicherte Seite angezeigt.

  • Alle weiteren Anfragen an die Seite innerhalb der ersten 10 Sekunden werden ebenfalls aus dem Cache bedient und sind sofort verfügbar.
  • Nach dem 10-Sekunden-Fenster zeigt die nächste Anfrage weiterhin die zwischengespeicherte (veraltete) Seite an.
  • Next.js löst eine Hintergrundgenerierung der Seite aus.
  • Sobald die Seite erfolgreich generiert wurde, wird der Cache von Next.js ungültig gemacht und die aktualisierte Seite angezeigt. Falls die Hintergrundgenerierung fehlschlägt, bleibt die alte Seite unverändert.

Wenn eine Anfrage an einen Pfad gestellt wird, der noch nicht generiert wurde, rendert Next.js die Seite serverseitig bei der ersten Anfrage. Zukünftige Anfragen werden die statische Datei aus dem Cache bedienen. ISR auf Vercel persistiert den Cache global und behandelt Rollbacks.

Wichtig: Überprüfen Sie, ob Ihr Upstream-Datenanbieter standardmäßig Caching aktiviert hat. Möglicherweise müssen Sie dies deaktivieren (z.B. useCdn: false), da eine Revalidierung sonst keine frischen Daten abrufen kann, um den ISR-Cache zu aktualisieren. Caching kann auf einer CDN auftreten (für einen angefragten Endpunkt), wenn dieser den Cache-Control-Header zurückgibt.

On-Demand Revalidation

Wenn Sie eine revalidate-Zeit von 60 festlegen, sehen alle Besucher für eine Minute dieselbe generierte Version Ihrer Website. Der einzige Weg, den Cache zu invalidieren, ist, wenn jemand die Seite nach Ablauf der Minute besucht.

Ab Version v12.2.0 unterstützt Next.js On-Demand Incremental Static Regeneration, um den Next.js-Cache manuell für eine bestimmte Seite zu leeren. Dies erleichtert die Aktualisierung Ihrer Website, wenn:

  • Inhalte aus Ihrem Headless-CMS erstellt oder aktualisiert werden
  • E-Commerce-Metadaten sich ändern (Preis, Beschreibung, Kategorie, Bewertungen etc.)

Innerhalb von getStaticProps müssen Sie kein revalidate angeben, um On-Demand Revalidation zu nutzen. Wenn revalidate weggelassen wird, verwendet Next.js den Standardwert false (keine Revalidierung) und validiert die Seite nur bei Bedarf neu, wenn revalidate() aufgerufen wird.

Wichtig: Middleware wird für On-Demand ISR-Anfragen nicht ausgeführt. Rufen Sie stattdessen revalidate() auf dem exakten Pfad auf, den Sie revalidieren möchten. Beispiel: Wenn Sie pages/blog/[slug].js und ein Rewrite von /post-1 -> /blog/post-1 haben, müssen Sie res.revalidate('/blog/post-1') aufrufen.

Verwendung von On-Demand Revalidation

Erstellen Sie zunächst ein geheimes Token, das nur Ihrer Next.js-App bekannt ist. Dieses Geheimnis wird verwendet, um unbefugten Zugriff auf die Revalidation-API-Route zu verhindern. Sie können die Route (manuell oder mit einem Webhook) mit folgender URL-Struktur aufrufen:

Terminal
https://<ihre-seite.de>/api/revalidate?secret=<token>

Fügen Sie das Geheimnis als Umgebungsvariable zu Ihrer Anwendung hinzu. Erstellen Sie anschließend die Revalidation-API-Route:

pages/api/revalidate.js
export default async function handler(req, res) {
  // Geheimnis überprüfen, um sicherzustellen, dass dies eine gültige Anfrage ist
  if (req.query.secret !== process.env.MY_SECRET_TOKEN) {
    return res.status(401).json({ message: 'Ungültiges Token' })
  }

  try {
    // Dies sollte der tatsächliche Pfad sein, kein umgeschriebener Pfad
    // z.B. für "/blog/[slug]" sollte dies "/blog/post-1" sein
    await res.revalidate('/pfad-zur-revalidierung')
    return res.json({ revalidated: true })
  } catch (err) {
    // Bei einem Fehler zeigt Next.js weiterhin
    // die zuletzt erfolgreich generierte Seite an
    return res.status(500).send('Fehler bei der Revalidierung')
  }
}

Sehen Sie sich unsere Demo an, um On-Demand Revalidation in Aktion zu sehen und Feedback zu geben.

Testen von On-Demand ISR während der Entwicklung

Bei lokaler Ausführung mit next dev wird getStaticProps bei jeder Anfrage aufgerufen. Um zu überprüfen, ob Ihre On-Demand ISR-Konfiguration korrekt ist, müssen Sie einen Produktionsbuild erstellen und den Produktionsserver starten:

Terminal
$ next build
$ next start

Anschließend können Sie bestätigen, dass statische Seiten erfolgreich revalidiert wurden.

Fehlerbehandlung und Revalidierung

Wenn bei der Hintergrundgenerierung ein Fehler in getStaticProps auftritt oder Sie manuell einen Fehler werfen, wird die zuletzt erfolgreich generierte Seite weiterhin angezeigt. Bei der nächsten Anfrage wird Next.js erneut versuchen, getStaticProps aufzurufen.

export async function getStaticProps() {
  // Wenn dieser Aufruf einen unbehandelten Fehler wirft, wird Next.js
  // die aktuell angezeigte Seite nicht invalidieren und
  // getStaticProps bei der nächsten Anfrage erneut aufrufen.
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  if (!res.ok) {
    // Bei einem Serverfehler können Sie einen Fehler werfen,
    // anstatt zurückzugeben, damit der Cache erst bei der
    // nächsten erfolgreichen Anfrage aktualisiert wird.
    throw new Error(`Fehler beim Abrufen der Posts, Status ${res.status}`)
  }

  // Bei erfolgreicher Anfrage werden die Posts zurückgegeben
  // und alle 10 Sekunden revalidiert.
  return {
    props: {
      posts,
    },
    revalidate: 10,
  }
}

Self-hosting ISR

Incremental Static Regeneration (ISR) funktioniert bei selbstgehosteten Next.js-Sites out of the box, wenn Sie next start verwenden.

Sie können diesen Ansatz verwenden, wenn Sie auf Container-Orchestratoren wie Kubernetes oder HashiCorp Nomad deployen. Standardmäßig werden generierte Assets im Speicher jedes Pods gespeichert. Das bedeutet, dass jeder Pod seine eigene Kopie der statischen Dateien hat. Veraltete Daten können angezeigt werden, bis der jeweilige Pod von einer Anfrage getroffen wird.

Um Konsistenz über alle Pods hinweg zu gewährleisten, können Sie das In-Memory-Caching deaktivieren. Dies weist den Next.js-Server an, nur Assets zu verwenden, die von ISR im Dateisystem generiert wurden.

Sie können ein gemeinsam genutztes Netzwerklaufwerk in Ihren Kubernetes-Pods (oder ähnlichem Setup) verwenden, um denselben Dateisystem-Cache zwischen verschiedenen Containern wiederzuverwenden. Durch die gemeinsame Nutzung desselben Mounts wird auch der .next-Ordner, der den next/image-Cache enthält, geteilt und wiederverwendet.

Um In-Memory-Caching zu deaktivieren, setzen Sie isrMemoryCacheSize in Ihrer next.config.js auf 0:

next.config.js
module.exports = {
  experimental: {
    // Standardmäßig 50MB
    isrMemoryCacheSize: 0, // Cache-Größe in Bytes
  },
}

Wichtig: Je nach Konfiguration Ihres gemeinsamen Mounts müssen Sie möglicherweise einen Race Condition zwischen mehreren Pods berücksichtigen, die gleichzeitig versuchen, den Cache zu aktualisieren.

Versionsverlauf

VersionÄnderungen
v12.2.0On-Demand ISR ist stabil
v12.1.0On-Demand ISR hinzugefügt (beta).
v12.0.0Bot-aware ISR Fallback hinzugefügt.
v9.5.0Base Path hinzugefügt.