Aug 20267 min read

Building PWAs with Next.js 16: A Practical Guide

How I turned a Next.js 16 app into an installable Progressive Web App — covering manifest.webmanifest, standalone mode, service workers, portrait lock, and offline-first UX patterns I used in HarKaam.

Next.jsPWAService WorkerMobile

Progressive Web Apps (PWAs) bridge the gap between a website and a native mobile app. As a Full Stack Developer based in Karachi, Pakistan, I have shipped one production PWA — HarKaam — and learned the hard way what actually matters when building one with Next.js 16.

Why a PWA?

For markets like Pakistan where mobile data is cheap and app store discovery is noisy, a PWA wins on three fronts: installable on Android without an APK, lightweight enough to load on 3G, and a single codebase that runs in any browser. I chose a PWA for HarKaam precisely because most customers in Karachi use Android devices and would never search a Play Store for a plumber.

The manifest.webmanifest File

Everything starts with a manifest. In Next.js, place it at public/manifest.webmanifest and reference it from the root layout via the metadata manifest field. The key fields are name, short_name, start_url, scope, display ("standalone" for native-like UX), orientation ("portrait" for mobile-first apps), background_color, theme_color, and an array of icons in 192×192 and 512×512.

Standalone Mode and Display Strategy

Setting display to "standalone" hides the browser chrome — no address bar, no reload button. This is what makes a PWA feel like an installed app. I pair it with orientation "portrait" for marketplace-style apps like HarKaam, where users browse service providers vertically. You can read how this fits into the broader HarKaam architecture in its case study.

Service Workers and Offline Support

Next.js 16 does not ship a service worker by default. I wrote a small one that caches the app shell (HTML, CSS, fonts) and falls back to a cached response when the network fails. Keep it under 5 KB — heavier service workers hurt first-load performance. Register it from a client component using navigator.serviceWorker.register.

Performance Budgets

A PWA is only as good as its load time on a mid-range Android device over 3G. I set a hard budget: 200 KB initial JS, all images in WebP, lazy-load below-the-fold images, and preconnect to font origins. My services page covers these in more detail.

The Payoff

After shipping HarKaam as a PWA, install-to-booking conversion was higher than the web version of the same flow. Users did not need to be convinced to "download an app" — they tapped "Add to Home Screen" once and treated it like any other app. For Full Stack Developers in Pakistan building for local markets, PWA is often the right answer.

Share this article

Spread the word — sharing supports independent writing.

Written by

Syed Muhammad Hasnain Abdi

Full Stack Developer & AI Application Developer based in Karachi, Pakistan. Available for freelance projects and full-time opportunities.