---
title: "Inkrementelle statische Builds in Astro 7.2: So habe ich meine Rebuild-Zeit um 39% reduziert"
description: "Wie inkrementelle statische Builds in Astro 7.2 den Rebuild eines einzelnen Beitrags von ~16,5s auf ~10s reduziert haben, indem 637 von 661 Seiten mit der richtigen cacheKey-Einrichtung aus dem Cache wiederhergestellt wurden."
source: "https://www.launchfa.st/de/blog/faster-astro-builds-incremental-static-builds"
author: "Rishi Raj Jain"
created_at: 2026-08-10T00:00:00.000Z
keywords: "astro, inkrementelle statische builds, incrementalBuild, cacheKey, getStaticPaths, astro 7.2, build-performance, content collections, starlight, launchfast"
---

> **Site index for agents**
> Fetch https://www.launchfa.st/llms.txt to discover every page on this site.
> Every page is also available as Markdown by appending `.md` to its URL.

<div />

Ich habe meine inkrementelle Rebuild-Zeit um etwa **39%** reduziert, von rund 16,5 Sekunden auf rund 10, indem ich inkrementelle statische Builds in [Astro 7.2](https://astro.build/blog/astro-720/) aktiviert habe.

Diese Seite prerendert bei jedem Produktions-Build 661 Seiten: 70 Blogbeiträge in drei Sprachen, Dokumentation, Feature-Seiten und Use-Case-Seiten. Die meisten dieser Seiten ändern sich zwischen Deployments nicht. Vor dieser Änderung wurden beim Bearbeiten eines einzelnen Beitrags trotzdem alle 661 neu gerendert.

Astro 7.2 erlaubt es einer prerenderten Route, aus `getStaticPaths` einen `cacheKey` zurückzugeben. Astro stellt die Seite aus dem vorherigen Build wieder her, wenn ihr Modulgraph und dieser Schlüssel beide unverändert sind. Nach dem Bearbeiten eines einzelnen Beitrags werden 637 von 661 Seiten aus dem Cache wiederhergestellt. Dieser Beitrag beschreibt, wie ich das eingerichtet habe.

## Voraussetzungen

- Astro 7.2 oder neuer
- Prerenderte Routen (`export const prerender = true`)
- [Bun](https://bun.sh) für die Starlight-Patch-Schritte weiter unten (npm/yarn/pnpm haben gleichwertige Patch-Tools)

## Schritt 1: Aktiviere das Flag

Um die inkrementellen Builds nutzen zu können, ist der erste Schritt das Upgrade auf 7.2 mit dem folgenden Befehl:

```bash
bun add astro@latest
```

Beachte, dass der Modus experimentell ist. Aktiviere ihn in `astro.config.mjs` mit der folgenden Änderung:

```js
export default defineConfig({
  experimental: {
    incrementalBuild: true,
  },
})
```

Nach dem Aktivieren des Flags haben die ersten beiden Builds gleich lange gedauert. Es wurden keine Seiten aus dem Cache wiederhergestellt. Kommen wir zur Concurrency!

## Schritt 2: Korrigiere die Concurrency-Einstellung

Astro deaktiviert den inkrementellen Cache, wenn Seiten parallel gerendert werden:

```js
// node_modules/astro/dist/core/build/generate.js
if (options.settings.config.experimental.incrementalBuild) {
  if (options.settings.config.build.concurrency > 1) {
    logger.warn(
      'build',
      'The incremental build cache is disabled because `build.concurrency` is greater than 1.',
    )
  } else {
    // load the cache and restore pages
  }
}
```

Ich hatte `build.concurrency` auf die Anzahl der CPUs gesetzt. Paralleles Rendern und das Wiederherstellen aus dem Cache funktionieren nicht zusammen, deshalb habe ich mein Override entfernt:

```js
// astro.config.mjs
// build: {
//   concurrency: Math.min(os.cpus().length, 12),   // removed
// }
```

Mit der Concurrency zurück auf dem Standardwert `1` verlierst du das parallele Rendern, gewinnst aber die Cache-Wiederherstellung. Beachte, dass dies nur hilft, wenn der Großteil deiner Seite zwischen den Builds unverändert bleibt.

## Schritt 3: Füge dem Blog einen Cache Key hinzu

Eine Route tritt dem Cache bei, indem sie aus `getStaticPaths` einen `cacheKey` zurückgibt. Astro verwendet eine Seite nur dann wieder, wenn ihr Modulgraph und dieser Schlüssel beide mit dem vorherigen Build übereinstimmen.

Content-Collection-Einträge haben einen `digest`, der sich ändert, wenn sich die Quelle des Eintrags ändert:

```js
export async function getStaticPaths() {
  const posts = await getCollection('blog')
  return posts.map((post) => ({
    params: { slug: post.data.slug },
    props: { post },
    cacheKey: post.digest,
  }))
}
```

`post.digest` allein reicht für meine Blog-Vorlage nicht aus.

## Schritt 4: Beziehe alles ein, was die Seite rendert

Eine Blog-Seite rendert hier:

- Drei verwandte Beiträge (Vorschau von Titel und Beschreibung)
- Die aktuelle Sponsor-Anzeige in der Seitenleiste

Keins von beiden ist Teil von `post.digest`. Mit nur dem Post-Digest als Schlüssel liefert der Cache eine veraltete Seite aus, wenn sich ein verwandter Beitrag oder die Sponsor-Kampagne ändert.

```ts
// src/lib/cache-key.ts
import { getActiveSponsor } from '@/lib/sponsor'

type WithDigest = { digest?: string | number }

export function buildContentCacheKey(post: WithDigest, related: WithDigest[] = []): string {
  const sponsor = getActiveSponsor()?.id ?? 'none'
  const relatedDigests = related.map((entry) => entry.digest ?? '').join('.')
  return [post.digest ?? '', relatedDigests, sponsor].map(String).join('|')
}
```

Der Blog in allen drei Sprachen und die Feature-Seiten verwenden diesen Schlüssel. Der Cache wird ungültig, wenn sich der Post-Text, eine verwandte Vorschau oder der aktive Sponsor ändert.

## Schritt 5: Use-Case-Seiten

Die Use-Case-Seiten sind die größte Gruppe auf der Seite: über 300 über alle Sprachen hinweg. Sie sind keine Content-Collection-Einträge. Sie werden aus TypeScript generiert, eine Seite pro Framework und Integration.

Die Daten sind importiertes TypeScript, also bereits im Modulgraph der Route. Astros Dependency-Hash invalidiert jede Use-Case-Seite, wenn sich die Daten ändern, mit oder ohne `cacheKey`. Der Modulgraph deckt die Sponsor-Anzeige nicht ab, deshalb braucht der Schlüssel nur den Slug und den aktiven Sponsor:

```ts
export function buildUseCaseCacheKey(useCase: { slug: string }, related: { slug: string }[] = []): string {
  const sponsor = getActiveSponsor()?.id ?? 'none'
  const relatedSlugs = related.map((entry) => entry.slug).join('.')
  return [useCase.slug, relatedSlugs, sponsor].join('|')
}
```

## Schritt 6: Docs-Seiten (Starlight-Patch)

Die Dokumentation läuft mit [Starlight](https://starlight.astro.build), das eine Catch-all-Route `[...slug]` einfügt. Es gibt in meinem Code kein `getStaticPaths`, dem ich einen Schlüssel hinzufügen könnte.

Zuerst habe ich versucht, die Route mit `src/pages/[...slug].astro` zu überschatten. Die Docs wurden aus dem Cache wiederhergestellt, aber Astro protokollierte für jeden Docs-Pfad einen Routenkonflikt. Zwei Routen beanspruchten dasselbe Muster.

Die Lösung ist, Starlights eingefügte Route zu patchen und sie mit `bun patch` zu verfolgen:

```bash
bun patch @astrojs/starlight
# edit node_modules/@astrojs/starlight/routes/static/index.astro
bun patch --commit 'node_modules/@astrojs/starlight'
```

Das schreibt einen Patch unter `patches/` und einen `patchedDependencies`-Eintrag in `package.json`. Bun wendet ihn bei jeder Installation erneut an:

```astro
---
// node_modules/@astrojs/starlight/routes/static/index.astro (patched)
import { paths } from '../../utils/routing';
import CommonPage from '../common.astro';
import { createHash } from 'node:crypto';

export const prerender = true;

export async function getStaticPaths() {
  const docsSetHash = createHash('sha1')
    .update(paths.map((p) => `${p.props?.entry?.id ?? ''}:${p.props?.entry?.digest ?? ''}`).sort().join('|'))
    .digest('hex');
  return paths.map((p) => ({ ...p, cacheKey: `${p.props?.entry?.digest ?? ''}|${docsSetHash}` }));
}
---
<CommonPage />
```

Jede Docs-Seite rendert eine gemeinsame Seitenleiste und Vor-/Zurück-Links aus dem gesamten Docs-Set. Der Schlüssel verwendet zwei Teile:

1. Den Eintrags-Digest (den Inhalt dieser Seite)
2. Einen Hash über jedes Dokument (Seitenleiste und Paginierung)

Wenn sich die Docs nicht geändert haben, werden alle 96 Docs-Seiten aus dem Cache wiederhergestellt.

## Ergebnisse

Ein vollständiger Cold-Build gegenüber einem inkrementellen Rebuild nach dem Bearbeiten eines einzelnen Beitrags, bei Concurrency 1:

| Build | Wiederhergestellte Seiten | Gesamtzeit |
| --- | --- | --- |
| Cold (Cache geleert) | 0 / 661 | ~16,5s |
| Inkrementell (ein Beitrag bearbeitet) | 637 / 661 | ~10s |

Rund **39%** schneller, sobald der Cache warm ist. Das Bearbeiten eines Beitrags rendert 24 Seiten neu, diesen Beitrag plus die stets dynamischen Index-Seiten, und stellt die übrigen 637 wieder her 🤯
