Nextjs Status Page: 90-Tage-Uptime-Balken und Störungen

Eine Statusseite klingt nach einem Wochenendprojekt, bis du aufschreibst, was sie alles leisten muss: jeden Dienst in einem Banner zusammenfassen, 90 Tage Uptime-Balken pro Komponente zeichnen, Updates zu Störungen in der richtigen Reihenfolge zeigen, bis zur Wartung herunterzählen, einen Verlauf führen und online bleiben, während deine App down ist. Dieses Tutorial baut eine nextjs status page im App Router, gespeist aus deinen eigenen Monitoring-Daten statt von einem gehosteten Anbieter. Die Oberfläche ist unsere Vorlage Status Page, wir sind also nicht neutral. Das Datenmodell, die Uptime-Rechnung und das Caching funktionieren aber genauso, wenn du eine Statusseite erstellen willst und deine React Status Page komplett selbst baust.
Was gehört auf eine öffentliche Statusseite?
Eine öffentliche Statusseite braucht sechs Teile, und die großen gehosteten Produkte haben Besucher darauf trainiert, nach allen zu suchen:
- Ein Gesamt-Banner. „All systems operational“ in Grün, Gelb für eingeschränkt oder teilweise gestört, Rot für einen schweren Ausfall, Blau für Wartung. Die schlechteste Komponente entscheidet.
- Komponenten mit Uptime-Balken. Eine Zeile für alles, was deine Kunden nutzen (API, Web-App, Webhooks), jede mit einem Balken aus Tagesblöcken. Atlassian Statuspage zeigt in seiner Uptime-Ansicht (opens in a new tab) (Stand Oktober 2026) die letzten 90 Tage, färbt jeden Tag von Grün über Gelb und Orange bis Rot, je näher die Ausfallzeit an 60 Minuten kommt, und zeigt Tage ohne Daten grau. OpenStatus (opens in a new tab) geht kürzer: Seit dem 24. Juni 2026 wählt jede Seite 30 oder 45 Tage.
- Offene Störungen mit ihren Updates. Investigating, identified, monitoring, resolved, das neueste oben, jedes mit Uhrzeit.
- Geplante Wartung. Was, wann und welche Komponenten.
- Eine Seite mit dem Störungsverlauf. Vergangene Störungen nach Tag gruppiert, damit die Frage „Lag es letzten Dienstag an euch oder an uns?“ eine Antwort hat.
- Eine Möglichkeit zum Abonnieren. E-Mail, RSS, Webhooks, ein Kalender für Wartungen.
Die meisten Treffer für „status page template“, die wir gefunden haben, sind entweder komplette selbst gehostete Produkte (eine Datenbank, ein Admin-Bereich, ein Monitor) oder ein statisches Mockup mit fest eingetragenen Balken. Der schwierige Teil liegt dazwischen: rohe Checks in ehrliche Tageswerte verwandeln und sie auf eine Seite bringen, die schnell und aktuell bleibt. Darum geht es hier hauptsächlich.
Wie installierst du die Vorlage für die Statusseite?
Ein CLI-Befehl kopiert die Vorlage und alles, was sie importiert. Die Vorlage gehört zu Pro, das Konto hinter der CLI braucht also Wingo UI Pro.
Die CLI kopiert components/templates/status-page.tsx und status-page-data.ts in dein Projekt, dazu alles, was die beiden nutzen: den Tracker für die Uptime-Balken, die Timeline für Updates zu Störungen, den Countdown für Wartungen und das Popover für das Formular zum Abonnieren. Ohne Daten-Props rendert die Vorlage einen von drei Beispieldatensätzen, den du mit simulate auswählst (operational, degraded oder outage). Praktisch für einen ersten Blick.
$ npx wingo-ui@latest add status-pageWelche Daten braucht eine Next.js-Statusseite?
Sie braucht vier Daten-Props, alle in status-page-data.ts typisiert. Texte und Links kommen getrennt über labels und hrefs.
Ein Tag im Verlauf einer Komponente ist ein StatusDay: { date, status, uptime, note? }. Dabei ist status einer der Werte ok, degraded, down, maintenance oder none, und uptime ist ein Prozentwert von 0 bis 100. Eine Störung bleibt offen, bis ihr neuestes Update die Phase resolved hat. Ein Wartungsfenster verschwindet, sobald endsAt vorbei ist.
Ein Detail erwischt dich gleich am ersten Tag: Lässt du groups, incidents oder maintenance weg, greift die Vorlage für dieses Prop auf ihre Beispieldaten zurück. Übergib also immer ein Array, auch ein leeres. Ein updatedAt, das sich nicht als Datum parsen lässt, fällt ebenfalls auf das Datum der Beispieldaten zurück.
Wie werden aus Monitoring-Checks tägliche Uptime-Balken?
Dein Monitor (ein gehosteter Pinger, ein Cronjob, ein Health Check in deinem eigenen Worker) liefert Check-Ergebnisse. Die Statusseite will eine Zeile pro Komponente und Tag. Fass das einmal zusammen, in einem geplanten Job oder einer SQL-View, und speichere die Minuten:
Dahinter steckt eine Festlegung, und die solltest du bewusst treffen. Unsere: Ausfallminuten zählen voll, Minuten mit eingeschränkter Leistung färben den Block gelb, senken den Prozentwert aber nicht, und Wartung wird herausgerechnet. Atlassian entscheidet anders: Laut seiner Doku (geprüft im Oktober 2026) zählen Teilausfälle mit 30 % eines schweren Ausfalls, eingeschränkte Leistung und Wartung zählen gar nicht. Wenn du das willst, ergänz DayMinutes um eine Spalte partial mit Minuten und berechne die Uptime aus measured - down - partial * 0.3. Egal, wofür du dich entscheidest: Veröffentliche die Regel neben den Balken (das Label componentsDescription ist ein guter Ort), damit Kunden deine Rechnung nachprüfen können.
Zwei weitere Regeln halten die Balken ehrlich. Fass die Tage in UTC zusammen, denn die Vorlage rendert jede Zeit in ihrem Prop timeZone, und das steht standardmäßig auf UTC, damit Server und Browser dasselbe ausgeben. Und beachte, dass ein Tag mit none den Wert uptime: 100 trägt: Der Durchschnitt einer Zeile zählt jeden Tag, den sie bekommt. Eine Komponente, die du letzte Woche angelegt hast, würde also einen perfekten 90-Tage-Wert zeigen. Kürz jeden Verlauf auf den Tag, an dem die Komponente live ging, so wie die Route unten mit createdAt. Atlassian löst dasselbe Problem mit einem Startdatum pro Komponente, das standardmäßig der Tag ist, an dem die Komponente angelegt wurde.
Wie baust du die Status-Route im App Router?
Teil sie auf: eine Server Component, die die Daten lädt und umformt, und einen kleinen Client-Wrapper für alles, was die Servergrenze nicht überqueren kann. Die Vorlage ist eine Client Component, und linkComponent und onSubscribe sind Funktionen, gehören also in den Wrapper. Die Daten gehen als reines JSON hinüber.
export const revalidate = 60 hält die Seite statisch und erzeugt sie höchstens einmal pro Minute neu. Das zählt genau in dem Moment, auf den es ankommt: Während eines Ausfalls hat deine Statusseite den meisten Traffic, und eine statische Seite aus dem Cache belastet die ohnehin angeschlagene Datenbank nicht zusätzlich. Der ISR-Guide von Next.js (opens in a new tab) sagt außerdem, dass bei einem Fehler in der Revalidierung weiter die zuletzt erfolgreich erzeugten Daten ausgeliefert werden. Eine fehlschlagende Abfrage zeigt also leicht veraltete Daten statt einer Fehlerseite.
Wenn dein Projekt cacheComponents einschaltet, wird ein revalidate-Export zum Build-Fehler. Verschieb dann das ganze Laden in eine async-Funktion, die mit "use cache" beginnt und cacheLife("minutes") aufruft (dieses Profil revalidiert nach einer Minute), und berechne auch today und updatedAt darin: Cache Components lässt das Prerendering bei einem nackten new Date() außerhalb eines gecachten Bereichs scheitern.
Zwei Dinge solltest du vor dem Launch prüfen:
onSubscribeist angeschlossen. Ohne das Prop wartet das Formular 900 ms und meldet Erfolg. Für eine Demo ist das richtig, für Kunden falsch. GibtonSubscribeein Promise zurück, dreht sich der Button, bis es erfüllt ist. Wird es abgelehnt, erscheint der Fehler.- Die Standardlinks existieren.
hrefszeigt auf/status/history,/status/feed.rss,/status/maintenance.icsund/docs/webhooks. Bau diese Routen oder überschreib die Links.
Wie aktualisierst du die Seite, sobald sich eine Störung ändert?
Eine Minute reicht für die Balken. Für „Investigating“ bei einem frischen Ausfall ist sie zu langsam. Richte den Webhook deines Monitors oder Incident-Tools auf einen Route Handler, der die Seite neu validiert:
Aus einem Route Handler aufgerufen, markiert revalidatePath die Seite als veraltet, und der nächste Besuch rendert sie frisch. Validier /status/history genauso neu, wenn du eine Störung abschließt.
Wie spielen Störungen, Wartung und Banner zusammen?
Das Banner setzt du nie von Hand. overall steht standardmäßig auf "auto" und ruft das exportierte deriveOverall(groups) auf: Der schlechteste Zustand einer Komponente gewinnt, in der Reihenfolge major, partial, degraded, maintenance, operational. Halte den state jeder Komponente aktuell, und das Banner folgt. Setz overall nur für den seltenen Fall explizit, den deine Daten nicht abbilden können, etwa ein geplantes Fenster für die ganze Plattform.
Eine offene Störung erscheint im Banner, ihre Updates als Timeline, das neueste oben. Speichere Updates als Zeilen mit stage, message und einer Zeit at, und leg ein neues an, sobald sich etwas ändert. isIncidentOpen(incident) liefert true, bis das neueste Update resolved sagt. Jede Störung führt die IDs der betroffenen Komponenten auf, so kann die Seite sie beim Namen nennen.
Wartungsfenster zählen bis startsAt herunter, während der Wartung dann bis endsAt, und verschwinden danach. Der Server rendert jedes Fenster als bevorstehend, und die Uhr wird erst nach der Hydration gelesen, danach alle 30 Sekunden. Eine statische Seite verursacht so nie einen Hydration Mismatch. Die Kehrseite: Ein Fenster, das nach der letzten Regenerierung zu Ende ging, steht im gecachten HTML noch als „Scheduled maintenance“, bis die Seite hydriert. Deshalb filtert die Route beendete Fenster heraus, bevor sie sie übergibt, und deshalb lohnt sich ein revalidatePath, wenn ein Fenster schließt.
Unter den Komponenten listet der Störungsverlauf die letzten historyDays Tage auf (standardmäßig 7), mit „No incidents reported“ an ruhigen Tagen. Das beantwortet die häufigste Frage. Verlinke hrefs.history auf eine vollständige Seite mit dem Störungsverlauf, die dieselbe Vorlage mit historyDays={30} rendert (und mit einem Label historyDescription, das „die letzten 30 Tage“ sagt), oder auf eine schlichte Liste aller Störungen nach Monat.
Wie verhalten sich Uptime-Balken auf Smartphones und mit der Tastatur?
Hier fällt eine Statusseite aus lauter divs meistens auseinander. Neunzig Blöcke auf einem 390px breiten Bildschirm sind nach Abzug der Lücken jeweils schmaler als 3px: unmöglich anzutippen und schwer zu lesen. Die Vorlage rendert zwei Tracker pro Komponente und lässt CSS entscheiden: 90 Tage ab 768px, darunter die letzten 30, jeder mit eigenem Durchschnitt. Der Wechsel ist eine Media Query (md:hidden und max-md:hidden). Das Server-HTML stimmt also schon, und nach der Hydration springt nichts. Ein Check mit useIsMobile kann das nicht versprechen (warum, erklären wir in unserem Artikel über den React Hook use mobile).
Bei Touch ist der ganze Balken die Zielfläche. Ein Tipp heftet eine Anzeige mit Datum, Uptime und Notiz an. Ziehst du seitwärts, wanderst du durch die Tage, während vertikales Ziehen weiter die Seite scrollt. Ein zweiter Tipp auf denselben Block löst onBlockClick aus, ein Tipp daneben blendet die Anzeige aus. Mit der Tastatur landet Tab auf dem neuesten Block, die Pfeiltasten gehen durch die Tage, Pos1 und Ende springen an die Enden, Bild auf und Bild ab bewegen sich um zehn, Enter oder Leertaste lösen onBlockClick aus, und eine Live-Region (polite) liest jeden Tag vor. Screenreader bekommen außerdem eine Zusammenfassung der Anzahl pro Status und eine Tabelle aller Blöcke.
Den Tracker kannst du auch allein nutzen, und dort landen die meisten Suchen nach „uptime bars react“: eine Karte im internen Dashboard, eine Zeile für den Sync-Zustand, die letzten 30 Läufe einer Integration. Allein geht er anders mit schmalen Bildschirmen um: fit="latest" (der Standard) behält nur die neuesten Blöcke, die bei minBlockWidth (4px) passen, und verschiebt die Beschriftung am Anfang entsprechend. Die Vorlage zeigt stattdessen immer genau 90 und 30 Tage, damit der Durchschnitt über dem Balken immer einen bekannten Zeitraum abdeckt.
Jeder Datenpunkt ist { status, id?, date?, label?, description? }, und statuses wird über die Standardwerte gelegt (ok, degraded, down, maintenance, none). Ein selbst erfundener Schlüssel wie partial bekommt so sein eigenes Label und seinen eigenen tone. Ein Status ohne Eintrag wird als none gezeichnet und loggt in der Entwicklung eine Warnung.
$ npx wingo-ui@latest add trackerWo solltest du eine Statusseite hosten?
Hoste sie auf einem anderen Deployment, bei einem anderen Anbieter und unter einer anderen Domain als die App, über die sie berichtet. Am 8. April 2021 lief die Statusseite von Facebook offenbar auf derselben Infrastruktur wie die Dienste, die ausfielen. Statuspal empfiehlt in seiner Analyse dieses Ausfalls (opens in a new tab) für alles Selbstgehostete eine eigene Infrastruktur, ein eigenes Rechenzentrum, einen eigenen Hosting-Anbieter und eine eigene Domain. Statuspal verkauft Statusseiten, gewichte den Rat also entsprechend. Die Logik trägt aber auch für sich allein.
Für eine Next.js-Statusseite heißt das dreierlei:
- Ein eigenes Deployment. Ein eigenes Projekt, keine Route in deiner Haupt-App. Ein fehlerhaftes Deployment oder ein abgestürzter App-Server sollte sie nicht mitreißen.
- Daten, die nicht von der Datenbank der App abhängen. Lass den Monitor die Rollups und Störungen in einen kleinen Speicher schreiben, den das Status-Projekt liest, oder schick sie ihm direkt. Kann die Seite nur rendern, indem sie die Datenbank abfragt, die gerade ausgefallen ist, steht nur noch dein Cache zwischen dir und einer leeren Seite.
- Monitoring von außen. Checks, die in dem System laufen, das sie prüfen, verstummen mit ihm.
Wenn du den Status auch in deiner App zeigen willst (ein Banner im Dashboard während einer Störung), lies dieselben Daten aus dem JSON des Status-Projekts, statt eine zweite Quelle der Wahrheit zu pflegen. Für die App-Seite baut unser Tutorial zum Next.js Admin Dashboard die Shell, Tabellen und Einstellungen drumherum, und weitere Screens wie diesen findest du in der Kategorie Build it.
Was ist der nächste Schritt?
Installier die Vorlage, render sie mit Beispieldaten und tausch dann deine Rollups Prop für Prop ein: zuerst groups, dann incidents, dann maintenance.
Die Vorlage Status Page und der Tracker gehören zu Wingo UI Pro; mehr dazu unter Pläne und Preise von Wingo UI Pro. Wenn du mit Claude Code oder Cursor baust, lässt der MCP-Server von Wingo UI deinen Agenten die Props und das Nutzungsbeispiel der Vorlage direkt lesen. Das hilft, wenn er die Zuordnung aus deinem Monitoring-Schema schreibt.
Häufige Fragen
Wie baue ich eine Statusseite in Next.js?
Leg eine Route app/status an, deren Server Component deine Komponenten, ihre tägliche Uptime und deine Störungen lädt und dann rendert. Exportiere revalidate = 60, damit die Seite statisch bleibt und sich trotzdem jede Minute erneuert, und ruf revalidatePath('/status') aus einem Webhook auf, sobald sich eine Störung ändert.
Wie wird der Uptime-Prozentsatz auf einer Statusseite berechnet?
Meist als Minuten, in denen eine Komponente erreichbar war, geteilt durch die gemessenen Minuten, pro Tag und dann über den Zeitraum gemittelt. Atlassian Statuspage zählt Stand Oktober 2026 Teilausfälle mit 30 % eines schweren Ausfalls und lässt eingeschränkte Leistung und Wartung außen vor. Leg deine eigene Regel fest und schreib sie auf.
Sollte eine Statusseite auf demselben Server wie meine App laufen?
Nein. Eine Statusseite, die sich Server, DNS oder ein Deployment mit deiner App teilt, kann im selben Ausfall offline gehen, über den sie berichten soll. Deploye sie als eigenes Projekt und schick ihr die Daten von einem Monitor, der woanders läuft.
Wie viele Tage Uptime-Verlauf sollte eine Statusseite zeigen?
Atlassian Statuspage zeigt 90 Tage; bei OpenStatus wählt laut Changelog vom 24. Juni 2026 jede Seite 30 oder 45 Tage (45 als Standard). Die Status Page von Wingo UI zeigt am Desktop 90 Tage und auf Smartphones die letzten 30, weil 90 Blöcke dort zu schmal zum Antippen wären.
Ist die Vorlage Status Page von Wingo UI kostenlos?
Nein, die Vorlage Status Page und der Tracker, den sie nutzt, gehören zu Wingo UI Pro. Du installierst sie mit npx wingo-ui@latest add status-page, sobald dein Konto Pro hat.
- Next.js
- Statusseite
- Uptime
- Vorlagen


