HTTP 429 Too Many Requests: Was Entwickler über Rate Limits übersehen
Dein Deploy geht Freitag um 16 Uhr live. Monitoring blinkt rot über drei Dashboards. Benutzer sehen 429-Fehler beim Checkout, beim Login, bei jedem API-Call, der zählt. Dein Rate Limiter lehnt Requests ab — oder noch schlimmer, eine Third-Party-API lehnt dich ab, und deine Retry-Logik macht es noch schlimmer. Der HTTP 429 Too Many Requests Status Code ist gerade das Einzige zwischen dir und einem freien Wochenende. Die meisten Entwickler wissen, dass 429 "langsamer machen" bedeutet. Was sie übersehen, ist welche Requests zu wiederholen sind, wann man exponentiell abfallen sollte, und wie man Retry-After-Header setzt, die die Todesspirale tatsächlich verhindern. Hier ist, was wirklich passiert, wenn deine API anfängt, Traffic abzulehnen.
Ich war auf beiden Seiten davon. Ich war der Entwickler, der versehentlich eine CMS-API wegen eines falsch konfigurierten Build-Prozesses DDoS-t hat, und ich war der, der Rate Limiting implementiert, um unsere eigenen Server vor außer Kontrolle geratenen Clients zu schützen. Beide Erfahrungen haben mir Dinge beigebracht, die die Docs nicht abdecken. Lass uns alles durchgehen.
Inhaltsverzeichnis
- Was bedeutet HTTP 429 wirklich?
- Häufige Ursachen für 429-Fehler
- Der Retry-After-Header erklärt
- Wie man 429-Fehler als Client behandelt
- Rate Limiting in Next.js API Routes implementieren
- Rate-Limiting-Strategien im Vergleich
- Rate Limiting in Astro und anderen Frameworks
- Überwachung und Debugging von 429-Fehlern in der Produktion
- FAQ

Was bedeutet HTTP 429 wirklich?
HTTP 429 ist in RFC 6585 definiert, veröffentlicht 2012. Die Spezifikation ist überraschend kurz. Hier ist der Kern: Der Benutzer (oder Client) hat zu viele Requests in einer bestimmten Zeitspanne gesendet.
Das war's. Es ist eine Rate-Limiting-Antwort. Der Server sagt: "Ich habe deinen Request verstanden, er ist wahrscheinlich gültig, aber du musst langsamer machen."
Das ist anders als 403 Forbidden (dir ist nicht erlaubt) oder 503 Service Unavailable (der ganze Server kämpft). Ein 429 ist gezielt. Es geht um deine Request-Rate speziell.
Die Antwort SOLLTE einen Retry-After-Header enthalten, der dem Client sagt, wie lange gewartet werden sollte, bevor erneut versucht wird. Ich sagte "sollte", weil viele APIs sich nicht darum kümmern, was allen das Leben schwerer macht.
Wo du 429s in der Praxis sehen wirst
- Third-Party-APIs: Stripe, OpenAI, GitHub, Contentful, Sanity — sie alle haben Rate Limits
- CDNs und Hosting-Plattformen: Vercel, Cloudflare und AWS werden 429s zurückgeben, wenn du ihre Edge-Rate-Limits erreichst
- Deine eigenen APIs: Wenn du Rate Limiting implementiert hast (und das solltest du)
- Build-Prozesse: Static Site Generation, die eine CMS-API für jede Seite trifft, kann leicht Rate Limits auslösen
- Web Scraping: Wenn du aggressiv Daten von externen Quellen abrufst
Häufige Ursachen für 429-Fehler
Lass mich die Szenarien, die ich tatsächlich in der Produktion erlebt habe, zusammenfassen, grob nach Häufigkeit geordnet.
1. Static Site Builds, die eine Headless CMS bombardieren
Das ist das, das Teams, die mit Headless-Architekturen arbeiten, am meisten trifft. Du hast eine Site mit 2.000 Seiten, jede braucht Daten von deinem CMS. Dein Build-Prozess feuert alle diese Requests parallel ab, das CMS sieht einen massiven Anstieg und fängt an, 429s zurückzugeben. Dein Build schlägt fehl.
Wir sehen das regelmäßig, wenn wir an Headless-CMS-Projekten arbeiten. Die Lösung beinhaltet Request-Queuing und Concurrency-Limits, die ich unten abdecke.
2. Fehlende oder kaputte Caching
Wenn jeder Seitenaufruf einen frischen API-Call auslöst, weil dein Caching-Layer nicht funktioniert, wirst du schnell Rate Limits treffen — besonders bei Traffic-Spitzen. Ich habe mal eine Next.js-App debuggt, bei der revalidate versehentlich auf 0 gesetzt war, was bedeutete, dass ISR effektiv deaktiviert war. Jeder Besucher löste einen neuen API-Call zu Contentful aus. Es brauchte etwa 45 Minuten echter Traffic, um 429s zu bekommen.
3. Retry-Schleifen ohne Backoff
Dein Code bekommt einen Fehler, versucht sofort erneut, bekommt einen weiteren Fehler, versucht sofort erneut... herzlichen Glückwunsch, du hast eine Rate-Limit-triggernde Maschine gebaut. Ich habe dieses Muster in Webhook-Handlern, Background Jobs und sogar Client-seitigen Fetch-Calls gesehen.
4. Mehrere Services, die einen API-Schlüssel teilen
Deine Staging-Umgebung, deine Produktionsumgebung, dein lokales Dev-Setup und deine CI/CD-Pipeline verwenden alle denselben API-Schlüssel. Jeder sieht einzeln gut aus, aber zusammen brennen sie durch dein Rate-Limit-Budget.
5. Client-seitiger Fetch ohne Debouncing
Eine Search-as-you-type-Funktion, die einen API-Call bei jedem Tastendruck auslöst. Ein Dashboard, das alle 500ms abruft. Ein Infinite Scroll, das Fetches schneller auslöst, als der Benutzer scrollen kann. Diese Muster können absolut 429s auslösen, besonders wenn sie über all deine Benutzer multipliziert werden.
6. Tatsächlicher Missbrauch oder Angriff
Manchmal macht eine 429 genau das, was sie sollte — deinen Server vor jemandem schützen, der eine unzumutbare Anzahl von Requests sendet. Bots, Credential Stuffing, Scraping — Rate Limiting ist deine erste Verteidigungslinie.
Der Retry-After-Header erklärt
Der Retry-After-Header ist die Art des Servers, dir genau zu sagen, wann du es erneut versuchen sollst. Es kann in zwei Formaten kommen:
Sekunden zum Warten:
HTTP/1.1 429 Too Many Requests
Retry-After: 60
Spezifisches Datum/Uhrzeit:
HTTP/1.1 429 Too Many Requests
Retry-After: Thu, 01 Jan 2026 00:00:00 GMT
Das Sekundenformat ist bei weitem häufiger. Das Datumsformat verwendet HTTP-date wie in RFC 7231 definiert.
Hier ist, was die meisten Tutorials dir nicht sagen: Viele APIs senden Retry-After überhaupt nicht, oder sie senden es inkonsistent. OpenAIs API enthält es im Allgemeinen. GitHubs API enthält es zusammen mit X-RateLimit-Reset. Viele kleinere APIs senden nur ein nacktes 429 und lassen dich raten.
Einige APIs senden auch zusätzliche Rate-Limit-Header:
| Header | Zweck | Beispiel |
|---|---|---|
X-RateLimit-Limit |
Max Requests pro Fenster | 100 |
X-RateLimit-Remaining |
Requests verbleibend im aktuellen Fenster | 0 |
X-RateLimit-Reset |
Unix-Timestamp, wenn das Fenster zurückgesetzt wird | 1735689600 |
Retry-After |
Sekunden zum Warten vor erneutem Versuch | 30 |
Überprüfe immer auf diese Header. Sie ermöglichen dir intelligerere Retry-Logik zu implementieren und sogar proaktiv zu verlangsamen, bevor du das Limit erreichst.

Wie man 429-Fehler als Client behandelt
Wenn du derjenige bist, der 429-Fehler bekommt, so handhabst du sie richtig.
Exponentielles Backoff mit Jitter
Das ist der Gold-Standard. Warte nicht einfach eine feste Zeit — erhöhe die Verzögerung exponentiell mit jedem Versuch, und füge etwas Zufälligkeit (Jitter) hinzu, um Thundering-Herd-Probleme zu verhindern.
async function fetchWithRetry(
url: string,
options: RequestInit = {},
maxRetries: number = 5
): Promise<Response> {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
const response = await fetch(url, options);
if (response.status !== 429) {
return response;
}
if (attempt === maxRetries) {
throw new Error(`Still getting 429 after ${maxRetries} retries`);
}
// Check for Retry-After header first
const retryAfter = response.headers.get('Retry-After');
let delay: number;
if (retryAfter) {
// Could be seconds or a date
const parsed = parseInt(retryAfter, 10);
if (!isNaN(parsed)) {
delay = parsed * 1000;
} else {
delay = new Date(retryAfter).getTime() - Date.now();
}
} else {
// Exponential backoff with jitter
const baseDelay = Math.pow(2, attempt) * 1000;
const jitter = Math.random() * 1000;
delay = baseDelay + jitter;
}
console.log(`Rate limited. Waiting ${Math.round(delay / 1000)}s before retry ${attempt + 1}`);
await new Promise(resolve => setTimeout(resolve, delay));
}
// TypeScript wants this, though we'll never reach it
throw new Error('Unexpected end of retry loop');
}
Request-Queuing für Build-Prozesse
Für Static Site Generation, bei der du hunderte oder tausende API-Calls machen musst, verwende eine Queue mit Concurrency-Kontrolle:
import pLimit from 'p-limit';
// Limit to 5 concurrent requests
const limit = pLimit(5);
const pages = await getAllPageSlugs(); // Returns ['/', '/about', '/blog/post-1', ...]
const results = await Promise.all(
pages.map(slug =>
limit(() => fetchWithRetry(`https://api.cms.com/pages/${slug}`))
)
);
Die p-limit-Bibliothek (2,5M+ wöchentliche npm-Downloads in 2026) ist mein Favorit dafür. Du kannst auch eine Verzögerung zwischen Requests hinzufügen:
const limit = pLimit(3);
const delay = (ms: number) => new Promise(r => setTimeout(r, ms));
const results = await Promise.all(
pages.map((slug, i) =>
limit(async () => {
if (i > 0) await delay(200); // 200ms between requests
return fetchWithRetry(`https://api.cms.com/pages/${slug}`);
})
)
);
Rate Limiting in Next.js API Routes implementieren
Jetzt wechseln wir zur anderen Seite — du baust eine API und musst sie schützen. Wenn du mit Next.js baust, so fügst du deinen API Routes Rate Limiting hinzu.
Einfacher In-Memory Rate Limiter
Für ein Single-Server-Deployment oder während der Entwicklung funktioniert das:
// lib/rate-limit.ts
type RateLimitEntry = {
count: number;
resetTime: number;
};
const rateLimitMap = new Map<string, RateLimitEntry>();
export function rateLimit({
windowMs = 60 * 1000,
maxRequests = 100,
}: {
windowMs?: number;
maxRequests?: number;
} = {}) {
return function check(identifier: string): {
allowed: boolean;
remaining: number;
resetIn: number;
} {
const now = Date.now();
const entry = rateLimitMap.get(identifier);
if (!entry || now > entry.resetTime) {
rateLimitMap.set(identifier, {
count: 1,
resetTime: now + windowMs,
});
return { allowed: true, remaining: maxRequests - 1, resetIn: windowMs };
}
if (entry.count >= maxRequests) {
return {
allowed: false,
remaining: 0,
resetIn: entry.resetTime - now,
};
}
entry.count++;
return {
allowed: true,
remaining: maxRequests - entry.count,
resetIn: entry.resetTime - now,
};
};
}
Verwenden in einer Next.js App Router API Route:
// app/api/data/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { rateLimit } from '@/lib/rate-limit';
const limiter = rateLimit({ windowMs: 60_000, maxRequests: 30 });
export async function GET(request: NextRequest) {
const ip = request.headers.get('x-forwarded-for') ?? 'anonymous';
const { allowed, remaining, resetIn } = limiter(ip);
if (!allowed) {
return NextResponse.json(
{ error: 'Too many requests. Please slow down.' },
{
status: 429,
headers: {
'Retry-After': String(Math.ceil(resetIn / 1000)),
'X-RateLimit-Limit': '30',
'X-RateLimit-Remaining': '0',
},
}
);
}
// Your actual route logic here
return NextResponse.json(
{ data: 'Here you go' },
{
headers: {
'X-RateLimit-Limit': '30',
'X-RateLimit-Remaining': String(remaining),
},
}
);
}
Production Rate Limiting mit Upstash Redis
Der In-Memory-Ansatz bricht zusammen, wenn du auf serverlosen Plattformen wie Vercel laufen, weil jede Funktionsaufrufe möglicherweise eine andere Instanz trifft. Du brauchst einen gemeinsamen Store. Upstash Redis ist die beliebteste Wahl dafür in 2026.
npm install @upstash/ratelimit @upstash/redis
// lib/rate-limit.ts
import { Ratelimit } from '@upstash/ratelimit';
import { Redis } from '@upstash/redis';
export const ratelimit = new Ratelimit({
redis: Redis.fromEnv(),
limiter: Ratelimit.slidingWindow(30, '60 s'),
analytics: true,
prefix: 'api-ratelimit',
});
// app/api/data/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { ratelimit } from '@/lib/rate-limit';
export async function GET(request: NextRequest) {
const ip = request.headers.get('x-forwarded-for') ?? '127.0.0.1';
const { success, limit, remaining, reset } = await ratelimit.limit(ip);
if (!success) {
const retryAfter = Math.ceil((reset - Date.now()) / 1000);
return NextResponse.json(
{ error: 'Rate limit exceeded' },
{
status: 429,
headers: {
'Retry-After': String(retryAfter),
'X-RateLimit-Limit': String(limit),
'X-RateLimit-Remaining': '0',
'X-RateLimit-Reset': String(reset),
},
}
);
}
return NextResponse.json({ data: 'Success' }, {
headers: {
'X-RateLimit-Limit': String(limit),
'X-RateLimit-Remaining': String(remaining),
},
});
}
Die kostenlose Tier von Upstash gibt dir 10.000 Requests/Tag, was für kleine Projekte ausreichend ist. Ihr Pro-Plan beginnt bei $10/Monat für 500K tägliche Commands ab Anfang 2026.
Middleware-Level Rate Limiting
Wenn du Rate Limiting über all deine API Routes haben möchtest, ist Next.js Middleware der richtige Ort:
// middleware.ts
import { NextRequest, NextResponse } from 'next/server';
import { ratelimit } from '@/lib/rate-limit';
export async function middleware(request: NextRequest) {
if (request.nextUrl.pathname.startsWith('/api/')) {
const ip = request.headers.get('x-forwarded-for') ?? '127.0.0.1';
const { success, reset } = await ratelimit.limit(ip);
if (!success) {
return NextResponse.json(
{ error: 'Too many requests' },
{
status: 429,
headers: {
'Retry-After': String(Math.ceil((reset - Date.now()) / 1000)),
},
}
);
}
}
return NextResponse.next();
}
export const config = {
matcher: '/api/:path*',
};
Rate-Limiting-Strategien im Vergleich
Nicht alle Rate-Limiting-Algorithmen sind gleich. Hier ist, wie die wichtigsten sich vergleichen:
| Algorithmus | Wie es funktioniert | Vorteile | Nachteile | Am besten für |
|---|---|---|---|---|
| Fixed Window | Zählt Requests in festen Zeitfenstern (z.B. pro Minute) | Einfach zu implementieren | Burst an Fenstergrenzen kann 2x das Limit ermöglichen | Einfache APIs, interne Tools |
| Sliding Window | Zählt Requests über einen rollierenden Zeitraum | Glattere Verteilung | Etwas komplexer, mehr Speicher | Die meisten Production APIs |
| Token Bucket | Token füllen sich mit konstanter Rate, jeder Request kostet einen Token | Ermöglicht kontrollierte Bursts | Komplexere State-Verwaltung | APIs, die Burst-Toleranz brauchen |
| Leaky Bucket | Requests treten in eine Queue ein und werden mit fester Rate verarbeitet | Sehr glatte Output-Rate | Kann Latenz hinzufügen, Requests können gelöscht werden | Webhook-Lieferung, Job-Verarbeitung |
| Sliding Window Log | Speichert Timestamp von jedem Request | Am genauesten | Hohe Speichernutzung in der Skalierung | Low-Volume, High-Accuracy-Bedarf |
Für die meisten Web-Anwendungen ist Sliding Window der sweet spot. Es ist das, was Upstash standardmäßig verwendet, und es ist das, was ich empfehlen würde, wenn du keinen spezifischen Grund hast, etwas anderes zu wählen.
Rate Limiting in Astro und anderen Frameworks
Wenn du mit Astro baust, funktioniert Rate Limiting anders, weil Astro primär ein Static-First-Framework ist. Aber mit Astros Server-Endpunkte (verfügbar im SSR-Modus) sind die Konzepte gleich:
// src/pages/api/data.ts
import type { APIRoute } from 'astro';
import { Ratelimit } from '@upstash/ratelimit';
import { Redis } from '@upstash/redis';
const ratelimit = new Ratelimit({
redis: Redis.fromEnv(),
limiter: Ratelimit.slidingWindow(30, '60 s'),
});
export const GET: APIRoute = async ({ request }) => {
const ip = request.headers.get('x-forwarded-for') ?? '127.0.0.1';
const { success, reset } = await ratelimit.limit(ip);
if (!success) {
return new Response(JSON.stringify({ error: 'Rate limit exceeded' }), {
status: 429,
headers: {
'Content-Type': 'application/json',
'Retry-After': String(Math.ceil((reset - Date.now()) / 1000)),
},
});
}
return new Response(JSON.stringify({ data: 'Hello' }), {
status: 200,
headers: { 'Content-Type': 'application/json' },
});
};
Für Edge-deployed Applications auf Cloudflare Workers möchtest du möglicherweise auch Cloudflares eingebaute Rate-Limiting-Regeln in Betracht ziehen, die auf Infrastructure-Ebene betrieben werden und viel mehr Traffic als Application-Level-Lösungen verarbeiten können. Ihr Advanced Rate Limiting beginnt bei $0,05 pro 10.000 guten Requests im Business-Plan.
Überwachung und Debugging von 429-Fehlern in der Produktion
Du kannst nicht beheben, was du nicht sehen kannst. Hier ist meine Checkliste für die Behandlung von 429-Fehlern in der Produktion:
Wenn du 429s erhältst
- Überprüfe, welche API 429 zurückgibt — Schau auf die Response-URL, nicht nur auf den Status Code
- Protokolliere den
Retry-After-Header — Wenn er konsistent sehr lang ist, brauchst du möglicherweise einen höheren Tier-Plan - Audit deine Request-Muster — Machst du redundante Calls? Kannst du Requests bündeln?
- Implementiere Caching — Verwende
stale-while-revalidate, Redis-Caching oder Next.js ISR, um API-Calls zu reduzieren - Überprüfe, ob mehrere Umgebungen API-Schlüssel teilen — Dies ist die häufigste "Geheimnis"-429-Ursache
Wenn du 429s sendest
- Richte Dashboards ein — Verfolge 429-Antwort-Raten über die Zeit
- Identifiziere Top-Offenders — Welche IP-Adressen oder API-Schlüssel treffen Limits am meisten?
- Überprüfe deine Limits — Sind sie zu restriktiv? Zu locker? Überprüfe deine Server-Kapazität und passe an
- Sende immer
Retry-After— Sei ein guter API-Bürger - Gib eine hilfreiche Fehlermeldung — Sag dem Client, welches Limit er getroffen hat und wann er erneut versuchen sollte
Eine gut gestaltete 429-Response-Body sieht so aus:
{
"error": {
"type": "rate_limit_exceeded",
"message": "You've exceeded 30 requests per minute. Please wait before retrying.",
"retryAfter": 42,
"documentation": "https://docs.yourapi.com/rate-limits"
}
}
Das ist unendlich hilfreicher als nur { "error": "Too many requests" }.
Wenn du mit anhaltenden Rate-Limiting-Problemen auf einer Headless-Architektur kämpfst — ob während Builds, zur Laufzeit oder beides — könnte es sich lohnen, Kontakt aufzunehmen, um deine Architektur zu besprechen. Wir haben viele dieser Probleme über verschiedene CMS- und Framework-Kombinationen hinweg gesehen und es gibt normalerweise eine Pattern-Level-Lösung, statt nur die Symptome zu verbinden.
FAQ
Was bedeutet HTTP 429 Too Many Requests?
HTTP 429 ist ein Status-Code, der bedeutet, dass du zu viele Requests an einen Server innerhalb eines bestimmten Zeitraums gesendet hast. Der Server limitiert dich deine Anfragen — es bittet dich, langsamer zu machen. Es ist kein Authentifizierungsfehler oder Serverfehler; deine Requests sind wahrscheinlich gültig, es sind einfach zu viele. Der Server sollte einen Retry-After-Header enthalten, der dir sagt, wann du erneut versuchen sollst.
Wie behebe ich einen 429-Fehler?
Wenn du 429-Fehler von einer API erhältst, implementiere Exponential Backoff mit Jitter in deiner Retry-Logik, reduziere deine Request-Frequenz, füge Caching hinzu, um redundante Calls zu vermeiden, und respektiere den Retry-After-Header. Wenn du das Limit während Builds erreichst, verwende Request-Queuing mit Concurrency-Limits. Wenn es konsistent passiert, brauchst du möglicherweise ein Upgrade zu einem höheren API-Plan mit großzügigeren Rate Limits.
Was ist der Retry-After-Header?
Der Retry-After-Header wird mit einer 429 (oder 503) Antwort gesendet, um dem Client zu sagen, wie lange gewartet werden sollte, bevor ein weiterer Request gemacht wird. Es kann als Anzahl von Sekunden angegeben werden (z.B. Retry-After: 60) oder als HTTP-Datum (z.B. Retry-After: Thu, 01 Jan 2026 00:00:00 GMT). Nicht alle APIs enthalten diesen Header, aber die gut gestalteten tun es.
Wie implementiere ich Rate Limiting in Next.js?
Für Entwicklung oder Single-Server-Deployments kannst du eine In-Memory-Map verwenden, um Request-Zählungen pro IP-Adresse zu verfolgen. Für Production-Serverless-Deployments auf Plattformen wie Vercel verwende Upstash Redis mit dem @upstash/ratelimit-Paket. Du kannst Rate Limiting auf der Individual-Route-Ebene oder über alle API Routes mit Next.js Middleware anwenden.
Was ist der Unterschied zwischen 429 und 503 Fehlern?
Ein 429 Too Many Requests ist speziell über Rate Limiting — dein Client sendet zu viele Requests. Ein 503 Service Unavailable bedeutet, der Server ist überlastet oder unter Wartung und kann keine Requests von jemandem bearbeiten. Beide können einen Retry-After-Header enthalten, aber sie zeigen sehr unterschiedliche Probleme an. Ein 429 ist auf dich gerichtet; ein 503 betrifft alle.
Kann Rate Limiting DDoS-Angriffe verhindern?
Rate Limiting ist eine Schutzebene gegen DDoS-Angriffe, aber es ist nicht allein ausreichend. Application-Level-Rate Limiting (wie du es in Next.js implementieren würdest) kann moderaten Missbrauch verarbeiten, aber ein ernsthafter DDoS-Angriff muss auf Infrastructure-Ebene gemindert werden — unter Verwendung von Services wie Cloudflare, AWS Shield oder den integrierten Schutzmaßnahmen deines Hosting-Providers. Denke an App-Level-Rate Limiting als ein Türsteher und Infrastructure-Level-Schutz als die Festungsmauern.
Welches Rate Limit sollte ich für meine API setzen?
Es hängt völlig von deinem Anwendungsfall ab. Ein häufiger Startpunkt für öffentliche APIs ist 60 Requests pro Minute pro IP, oder 1.000 Requests pro Stunde pro API-Schlüssel. Für authentifizierte Benutzer kannst du mehr erlauben. Der Schlüssel ist, echte Nutzungsmuster zu beobachten, Limits zu setzen, die legitime Nutzung mit etwas Spielraum ermöglichen, und basierend auf echten Daten anzupassen. Starten Sie restriktiver und lockern Sie — es ist leichter, als Limits zu verschärfen, nachdem Benutzer von höheren Raten abhängig werden.
Warum bekomme ich 429-Fehler während meines Static Site Builds?
Static Site Generatoren wie Next.js und Astro abrufen Daten für jede Seite zur Build-Zeit. Wenn du hunderte oder tausende von Seiten hast, das sind hunderte oder tausende von API-Calls in schneller Folge. Die meisten CMS-APIs haben Rate Limits zwischen 5-20 Requests pro Sekunde. Verwende p-limit oder ähnliche Bibliotheken, um Concurrency auf 3-5 gleichzeitige Requests zu limitieren, füge kleine Verzögerungen zwischen Batches hinzu, und erwäge, inkrementelle Builds zu verwenden (ISR in Next.js oder Astros inkrementelle Content Collections), um zu vermeiden, dass alles auf einmal neu gebaut wird.