I turned two of my live Next.js apps, Planzia and Quick Onboard Doc, into installable PWAs. Neither one took a weekend. This is the exact path I followed with next-pwa, including the parts most tutorials skip.
Why bother with a PWA
A PWA got me three things I actually wanted: an install prompt so the app sits on a home screen, offline access to content people have already loaded, and faster repeat visits from cached assets. Next.js is already halfway there thanks to code splitting and its routing, so most of the work is configuration, not rewriting your app.
1. Install and wire up next-pwa
next-pwa wraps your Next config and generates the service worker for you.
// next.config.js
const withPWA = require("next-pwa")({
dest: "public",
disable: process.env.NODE_ENV === "development",
})
module.exports = withPWA({
reactStrictMode: true,
})That `disable` line matters more than it looks. A service worker caching your dev build will keep handing you stale pages and make you think you're losing your mind. Turn it off in development.
2. The manifest
The manifest is a small JSON file that tells the operating system what your app is called, which icons to use, and how it should open. I keep it in `public/manifest.json` and link it from the root layout.
Get the icons right or the install prompt just won't fire. You need at least a 192px and a 512px icon, plus a 512px maskable one if you don't want Android cropping your logo badly.
3. Caching is where the real decisions live
This is the part that's an actual judgment call, not a copy-paste. For Quick Onboard Doc, the chat shell is identical on every visit, so I cache it Cache First: load instantly from cache, don't wait on the network. The document data behind it is different. It has to be fresh, so that goes Network First and only falls back to cache when there's no connection.
The wrong caching strategy doesn't crash anything. It quietly serves people yesterday's data, which is worse, because nobody notices for a while.
4. An offline page that isn't the browser dinosaur
When a request fails and there's no cache, the browser shows its own "no internet" screen. I'd rather show mine. I add a cached `/offline` route and point the service worker at it as a fallback, so the app still feels like the app even with the wifi off.
5. Test it like a user, not a dev
Run Lighthouse in Chrome DevTools for the PWA audit, but don't stop there. Actually install both apps. I install on Android and on desktop, kill my wifi, and click around. iOS Safari is the one that will embarrass you, so test there on purpose.
The whole thing is reversible and incremental. I shipped it to Planzia first, watched it for a week, then did Quick Onboard Doc.

Planzia
A planning and task app for managing projects, tasks, budgets, and teams, with subscriptions, file uploads, and transactional email, on serverless Postgres.

QuickOnboardDoc
An AI onboarding assistant that answers staff questions from a company's own documents using RAG, with multi-tenant workspaces and Google sign-in.


