Incrementelle statische Regenerierung

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 Site 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-Property 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 Server-Seite aufgerufen.
// Sie kann erneut aufgerufen werden, in einer serverlosen Funktion,
// wenn 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 alle 10 Sekunden
    revalidate: 10, // In Sekunden
  }
}

// Diese Funktion wird beim Build auf der Server-Seite 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 Posts für 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
  // auf dem Server, 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 innerhalb der ersten 10 Sekunden werden ebenfalls aus dem Cache bedient und sind sofort verfügbar.
  • Nach dem 10-Sekunden-Fenster wird die nächste Anfrage weiterhin die zwischengespeicherte (veraltete) Seite anzeigen
  • Next.js löst eine Hintergrundgenerierung der Seite aus.
  • Sobald die Seite erfolgreich generiert wurde, wird Next.js den Cache ungültig machen und die aktualisierte Seite anzeigen. Falls die Hintergrundgenerierung fehlschlägt, bleibt die alte Seite unverändert.

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

Wichtig: Überprüfen Sie, ob Ihr Upstream-Datenanbieter Caching standardmäßig 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 erfolgen (für einen angefragten Endpunkt), wenn dieser den Cache-Control-Header zurückgibt.

On-Demand Revalidierung

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 revalidate nicht angeben, um On-Demand-Revalidierung zu nutzen. Wenn revalidate weggelassen wird, verwendet Next.js den Standardwert false (keine Revalidierung) und validiert die Seite nur bei Aufruf von revalidate() neu.

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 Revalidierung

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

Terminal
https://<your-site.com>/api/revalidate?secret=<token>

Fügen Sie das Geheimnis als Umgebungsvariable zu Ihrer Anwendung hinzu. Erstellen Sie dann die Revalidierungs-API-Route:

pages/api/revalidate.js
export default async function handler(req, res) {
  // Geheimnis prüfen, um die Anfrage zu validieren
  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
    // z.B. für "/blog/[slug]" sollte dies "/blog/post-1" sein
    await res.revalidate('/path-to-revalidate')
    return res.json({ revalidated: true })
  } catch (err) {
    // Bei einem Fehler zeigt Next.js weiterhin
    // die letzte erfolgreich generierte Seite an
    return res.status(500).send('Fehler bei der Revalidierung')
  }
}

Sehen Sie sich unsere Demo an, um On-Demand-Revalidierung 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 Produktions-Build erstellen und den Produktions-Server 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 verursacht, 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 mit ISR

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

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. Dadurch wird der Next.js-Server angewiesen, 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 derselben Einbindung 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: {
    // Standardwert ist 50MB
    isrMemoryCacheSize: 0, // Cache-Größe in Bytes
  },
}

Wichtig: Je nach Konfiguration Ihrer gemeinsamen Einbindung 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.