Next.js PWA ohne next-pwa: Offline-Seite und App Shell
Eine Next.js PWA ist eine ganz normale App-Router-App mit ein paar zusätzlichen Dateien: einem Web App Manifest, Icons, einem Service Worker und einem Layout, das auch ohne die Bedienleisten des Browsers gut aussieht. Der offizielle Guide deckt das Manifest und Push-Benachrichtigungen ab. Viele Tutorials installieren danach next-pwa, ein Webpack-Plugin, in ein Framework, das inzwischen standardmäßig mit Turbopack baut. Dieses Tutorial nimmt für Next.js 16 einen schlankeren Weg: einen selbst geschriebenen Worker, der eine Offline-Seite zeigt, einen Install Prompt und eine App Shell mit Top Bar und Bottom Tabs, die Notch und Home-Indikator freihalten.
Was braucht eine Next.js PWA im Jahr 2026?
Weniger, als ältere Guides vermuten lassen. Hier ist die komplette Liste für eine Next.js PWA mit dem App Router, jeweils mit dem, was dir das Teil bringt:
Die Regeln zur Installierbarkeit pro Browser, auch warum Chrome sein Install-Event beim ersten Besuch zurückhalten kann, stehen in unserem Guide zum React PWA Install Prompt. Dieser Beitrag wiederholt sie deshalb nicht.
Wie fügst du im App Router ein Web App Manifest hinzu?
Über die Dateikonvention manifest. Eine app/manifest.ts, die eine Funktion als Default exportiert, wird unter /manifest.webmanifest ausgeliefert und automatisch im <head> jeder Seite verlinkt:
Leg die drei PNGs in public/. Beim maskierbaren Icon bleibt das Logo innerhalb der mittleren 80%, damit Android es zu einem Kreis oder einem Squircle zuschneiden kann. Fürs iPhone legst du eine app/apple-icon.png mit 180x180 neben das Layout; Next.js macht daraus den Link apple-touch-icon.
Dann sagst du dem Browser, wie die installierte App dargestellt werden soll. viewport und metadata sind im App Router getrennte Exporte, und beide funktionieren nur in Server Components:
viewportFit: "cover" ist wichtiger, als es aussieht. Ohne diese Einstellung zeigt iOS die Seite mit Rändern oben und unten, und env(safe-area-inset-*) bleibt 0. Komponenten, die die Safe Areas per Padding freihalten, laufen dann ins Leere. Mit der Einstellung läuft die Seite unter der Statusleiste und dem Home-Indikator durch, und Header und Tab Bar müssen diesen Platz wieder hinzufügen. Genau das macht die Shell weiter unten.
Ein Haken beim iPhone: statusBarStyle: "black-translucent" sorgt dafür, dass die installierte App unter der Statusleiste zeichnen darf, lässt Uhrzeit und Akkuanzeige aber weiß. Gib der Top Bar im Light Mode deshalb eine ausreichend dunkle Füllung, oder nimm "default" für eine undurchsichtige Statusleiste über der Seite. Der obere Inset ist dann einfach 0.
Brauchst du für eine Next.js 16 PWA noch next-pwa?
Nein. Die letzte Version des ursprünglichen Plugins next-pwa (opens in a new tab), 5.6.0, ist im August 2022 erschienen, und der gepflegte Fork @ducanh2912/next-pwa (opens in a new tab) hat zuletzt im September 2024 die Version 10.2.9 veröffentlicht (npm-Registry, geprüft am 5. November 2026). Beide hängen sich in Webpack ein, während Next.js 16 next dev und next build mit Turbopack ausführt, solange du nicht --webpack übergibst. Laut Upgrade-Guide für Next.js 16 (opens in a new tab) schlägt next build fehl, wenn es eine Webpack-Konfiguration findet, und auch ein Plugin, das eine hinzufügt, zählt dazu. Eine Next.js 16 PWA auf Basis von next-pwa bleibt also entweder mit --webpack bei Webpack oder wird mit next build --turbopack, das die Konfiguration ignoriert, ohne generierten Worker ausgeliefert.
Zwei Optionen funktionieren mit Turbopack:
- Ein selbst geschriebener Worker für eine Offline-Seite und Push. Das ist eine einzige Datei in
public/, ohne Build-Schritt und ohne Abhängigkeit. Den baut dieser Beitrag. - Serwist (opens in a new tab), wenn du Routen vorab cachen und Assets mit Strategien im Stil von Workbox cachen willst. Das Paket
@serwist/turbopack(9.5.13, 4. Oktober 2026) liefert den Worker über einen Route Handler aus, der mitcreateSerwistRoutegebaut wird, kompiliertapp/sw.tsmit esbuild und legt einenSerwistProviderum den Baum. Auch der Next.js-Guide zu PWAs (opens in a new tab) verweist für vollständiges Offline-Caching auf Serwist.
Fang mit dem selbst geschriebenen Worker an. Steig erst an dem Tag auf Serwist um, an dem du gecachte Daten-Screens brauchst, nicht früher, denn jedes gecachte Asset ist eine Version, die du irgendwann wieder ablaufen lassen musst.
Wie zeigst du in einer Next.js PWA eine Offline-Seite?
Fang gescheiterte Seitenaufrufe im Worker ab und beantworte sie mit einer Seite, die du bei der Installation gecacht hast. Das ist das web.dev-Rezept für eine Offline-Fallback-Seite (opens in a new tab), angepasst an Next.js. Es ist das schlankste Next.js PWA Offline-Setup, das sich trotzdem wie eine App anfühlt statt wie der Dinosaurier des Browsers.
1. Eine eigenständige Offline-Seite
Mach die Offline-Seite nicht zu einer Next.js-Route. Ihr CSS und JavaScript liegen in gehashten Dateien unter /_next/static, die dein Worker nie gecacht hat, also würde sie offline als HTML ohne Styles laden. Schreib stattdessen einfaches HTML mit Inline-Styles:
2. Der Service Worker
skipWaiting() und clients.claim() sind hier unbedenklich, weil dieser Worker keinen App-Code ausliefert. Sobald ein Worker deine JavaScript-Chunks cacht, kann ein neuer Worker, der unter einem offenen Tab aktiv wird, alte und neue Dateien mischen, und dann brauchst du stattdessen einen Hinweis „Update verfügbar“. Erhöh CACHE auf offline-v2, sobald sich offline.html ändert; der activate-Schritt löscht den alten Cache.
3. Registrier ihn aus einer Client-Komponente
updateViaCache: "none" sorgt dafür, dass die Update-Prüfung bei Navigationen sw.js vom Server holt statt aus dem HTTP-Cache. Sichere das mit einem Header ab, damit auch CDNs keinen alten Worker vorhalten:
4. Teste ihn
Führ next build && next start aus und öffne http://localhost:3000. localhost ist ein sicherer Kontext, du brauchst also kein Zertifikat. In den Chrome DevTools listet Application das Manifest und den aktiven Worker auf. Stell das Network-Panel auf Offline und lad neu: Statt der Fehlerseite des Browsers bekommst du deine eigene Seite.
Was passiert mit clientseitigen Navigationen, wenn das Netz wegfällt?
Sie scheitern wie jede andere Anfrage, denn der Worker oben sieht nur komplette Seitenaufrufe. Ein Tipp auf einen <Link> holt per fetch() eine Payload für React Server Components, keine Navigationsanfrage, also lässt der Worker sie zum Netz durch. Next.js 16 hat für diese Ebene eine Lösung, die noch als experimentell markiert ist: Mit experimental.useOffline: true in next.config.ts bleibt eine gescheiterte Navigation, ein Prefetch oder eine Server Action ausstehend und wird wiederholt, sobald die Verbindung zurück ist, und der Hook useOffline() aus next/offline sagt deiner UI, dass sie offline ist. Der Guide zum Offline-Support (opens in a new tab) zeigt darauf aufbauend ein Banner im Root-Layout. Betrachte das vorerst als nettes Extra und behalte den Worker als Sicherheitsnetz, denn ein experimentelles Flag kann sich zwischen Minor-Versionen ändern.
Wie fügst du einer Next.js PWA einen Install Prompt hinzu?
Binde die Komponente im Root-Layout ein, denn Chrome feuert beforeinstallprompt früh im Seitenaufbau, und eine Komponente, die erst später auf einer einzelnen Route mountet, kann das Event verpassen. Alle Details, von beforeinstallprompt über das Teilen-Menü auf dem iPhone bis zu der Frage, wann du besser nicht fragst, steht in React PWA Install Prompt für Chrome, Edge und iPhone. Die Kurzfassung mit unserem Install Prompt:
In Chrome und Edge zeigt er den Installationsdialog des Browsers, auf dem iPhone die Schritte für „Zum Home-Bildschirm“. In der installierten App und in In-App-Browsern bleibt er verborgen, und ein Wegklicken merkt er sich standardmäßig 14 Tage lang. Auf dem Smartphone sitzt er über der Bottom Tab Bar aus dem nächsten Abschnitt, weil er deren --bottom-bar-offset ausliest. Die Offline-Seite aus dem vorigen Abschnitt macht „auch offline“ zu einem ehrlichen Versprechen.
Wie fühlt sich eine Next.js PWA auf dem Smartphone nativ an?
Gib der installierten App ihre eigenen Bedienleisten. Im Modus standalone gibt es keine Adressleiste und keinen Zurück-Button, also muss die App einen Header, einen Weg zurück und eine Hauptnavigation in Reichweite des Daumens mitbringen. Auf dem Smartphone heißt das: eine Top Bar und eine Bottom Tab Bar, beide mit Abstand für die Safe Areas, die du mit viewportFit: "cover" geöffnet hast.
Die App Shell erledigt das als ein einziges Layout: Sidebar und Top Bar auf dem Desktop, eine Drawer-Navigation und eine Bottom Tab Bar unter 768px. Zieh die Demo unten auf Smartphone-Breite zusammen oder öffne sie auf deinem Smartphone und wechsle unten die Tabs:
$ npx wingo-ui@latest add app-shellInstallier sie mit npx wingo-ui@latest add app-shell; das kopiert auch Sidebar, Topbar und Bottom Tab Bar mit, die sie importiert. Dann machst du sie zum Layout der Routen für angemeldete Nutzer. Zuerst ein Provider, damit jeder Tab und jeder Sidebar-Link über next/link gerendert wird:
Pack {children} im Root-Layout in <Providers> und bau dann die Shell:
Drei Details sorgen dafür, dass sie sich installiert anfühlt und nicht wie eine eingebettete Webseite:
- Safe Areas. Die Topbar rechnet
env(safe-area-inset-top)als Padding ein, die Bottom Tab Barenv(safe-area-inset-bottom), beides standardmäßig aktiv (safeArea). Unser Beitrag zu Tailwind Safe Area Insets deckt den Rest der Seite ab. - Echte Viewport-Höhe. Die Shell bemisst sich mit
dvhstattvh, also endet eine kurze Seite am sichtbaren unteren Rand und nicht hinter der Toolbar von Safari. Die Hintergründe stehen in 100vh auf dem Smartphone und dvh in Tailwind. - Scrollen im Fenster. Mit dem Standard
scroll="window"funktioniert die Wiederherstellung der Scrollposition durch den Router weiter, und die fixierte Tab Bar schreibt--bottom-bar-offset, damit schwebende Buttons ihr ausweichen.
Blende reine Browser-UI in der installierten App aus
Ein Marketing-Footer oder ein Link „App holen“ wirkt in der App selbst seltsam. Ergänz in app/globals.css eine Variante für den Display-Modus in Tailwind v4:
Dann entfernt className="standalone:hidden" ein Element nur in der installierten App, und standalone:pb-4 kann Platz hinzufügen, der nur dort zählt. Es ist CSS, also stimmt es schon beim ersten Paint, ohne Flackern bei der Hydration.
Starte mit einem fertigen Home-Screen
Für eine Consumer-App ist der Block Mobile App Home ein kompletter erster Screen auf Basis derselben Tab Bar: ein großer Titel, der beim Scrollen in die Leiste schrumpft, Suche, Stories, Schnellaktionen, Feed-Tabs und Pull to Refresh. Scroll ihn, zieh oben nach unten und wechsle die Feed-Tabs:
$ npx wingo-ui@latest add mobile-app-homeMit der Prop desktop="full" streckt er sich auf dem Tablet über die volle Breite, statt eine zentrierte Spalte mit 440px zu behalten. Das passt zu einer installierten App auf dem iPad.
Was solltest du vor dem Release der PWA prüfen?
Sechs Checks, wo möglich auf echten Geräten, denn die DevTools zeigen dir weder die Notch noch das Icon im Launcher noch den Flugmodus:
- Manifest. In den DevTools zeigt Application, dann Manifest keine Fehler, und beide Icon-Größen laden.
- Offline. Installier die App, schalte den Flugmodus ein und öffne sie: Du siehst
offline.html, und sie lädt neu, sobald die Verbindung zurück ist. - iPhone. Füg sie in Safari zum Home-Bildschirm hinzu. Der Text in der Statusleiste ist über deiner Top Bar lesbar, nichts liegt unter der Notch, und die Tab Bar hält Abstand zum Home-Indikator.
- Android. Installier sie aus Chrome, prüf das maskierbare Icon im Launcher und dreh das Smartphone einmal.
- Updates. Ändere
offline.html, erhöhCACHE, deploye und öffne die App zweimal: Die neue Seite erscheint, und die DevTools listen einen einzigen Cache. - Desktop. Installier sie aus Chrome oder Edge; die Shell sollte im eigenen Fenster das Layout mit Sidebar zeigen.
Wenn du eigentlich nach einem Nextjs PWA Template gesucht hast, lass diese Checkliste darüber laufen, bevor du es übernimmst. Schritt 3 ist der, den dir ein Desktop-Browser nicht abnehmen kann.
Was solltest du als Nächstes bauen?
Liefer zuerst die vier Dateien aus: app/manifest.ts, public/offline.html, public/sw.js und die Register-Komponente. Sie sind reines Next.js, kostenlos und geben dir eine installierbare App mit einem ehrlichen Offline-Zustand. Für die Schicht der installierten App kopiert npx wingo-ui@latest add app-shell install-prompt die Shell, die Bottom Tabs und das Installationsbanner als Quellcode in dein Projekt; sie gehören zu Wingo UI Pro ($8 im Monat, $80 im Jahr oder $150 einmalig). Mehr Muster für Apps, die man mit einer Hand hält, findest du im Pillar-Beitrag zu Mobile-first React-Komponenten und in der Kategorie Mobile UI in React, und React Native vs PWA hilft dir, falls du noch abwägst, ob das Web reicht.
Häufige Fragen
Funktioniert next-pwa mit Next.js 16?
Nicht ohne Weiteres. Das ursprüngliche Paket next-pwa ist ein Webpack-Plugin, dessen letzte Version 5.6.0 aus dem August 2022 stammt, und Next.js 16 baut mit Turbopack. next build bricht deshalb an der Webpack-Konfiguration ab, die das Plugin hinzufügt, solange du nicht --webpack übergibst. Nimm für eine Offline-Seite einen selbst geschriebenen Service Worker, oder Serwist, dessen Paket @serwist/turbopack (9.5.13, Oktober 2026) in der Doku ein Setup für Turbopack hat.
Braucht eine Next.js PWA einen Service Worker, um installierbar zu sein?
In aktuellen Chromium-Browsern und auf dem iPhone nicht: Ein Manifest mit name, Icons in 192px und 512px, start_url und standalone-Display, über HTTPS ausgeliefert, reicht für die Installation aus dem Browsermenü. Für eine Offline-Seite, Push-Benachrichtigungen und das automatische beforeinstallprompt-Event in Chrome willst du trotzdem einen.
Warum erscheint meine Offline-Seite in Next.js ohne Styles?
CSS und JavaScript der Seite liegen in gehashten Dateien unter /_next/static, die dein Worker nie gecacht hat. Offline lädt also das HTML, das Stylesheet aber nicht. Halte die Offline-Seite eigenständig, mit Inline-CSS in public/offline.html, so wie es das Offline-Fallback-Rezept von web.dev vorsieht.
Wie teste ich einen Service Worker in Next.js lokal?
Führ next build und next start aus und öffne http://localhost:3000 (opens in a new tab). localhost gilt als sicherer Kontext, der Worker registriert sich also ohne HTTPS. In den Chrome DevTools zeigt Application das Manifest und den Worker, und mit der Option Offline im Network-Panel lädst du die Seite neu und landest auf der Offline-Seite.
Gibt es ein Next.js PWA Template mit App Shell?
App Shell, Bottom Tab Bar, Install Prompt und der Block Mobile App Home von Wingo UI liefern die Schicht für die installierte App: Top Bar, Bottom Tabs mit Safe Areas, eine Drawer-Navigation auf dem Smartphone und ein Installationsbanner. Sie gehören zu Pro und werden mit npx wingo-ui@latest add als Quellcode installiert.
- Mobile UI
- PWA
- Next.js
- Service Worker
- App Router

