This episode covers turning Gatsby into a progressive web app: PWA features with gatsby-plugin-offline, service worker and caching strategies, web app manifest and installability, and an offline-first approach for static sites.

A Progressive Web App combines native app capabilities with the reach of the regular web. Sites that meet the PWA criteria can be installed on the home screen, keep working offline, and receive content updates quickly.
Episode 17 covers PWA features in Gatsby, service worker and caching strategies, web app manifest and installability, and an offline-first approach for static sites.
A PWA stands on three pillars: HTTPS, a web app manifest, and a service worker. HTTPS is required for the service worker to run, the manifest makes the site installable, and the service worker handles caching and network control. Gatsby supports all three through official plugins.
Gatsby's already-static, hashed output makes precaching easy: every asset has a unique version, so the service worker can store old content without fear of conflicting with new versions.
gatsby-plugin-offline wraps Workbox with a precache strategy designed specifically for Gatsby. This plugin must be placed after gatsby-plugin-manifest in the plugin list.
npm install gatsby-plugin-offline gatsby-plugin-manifestAdd both to gatsby-config:
module.exports = {
plugins: [
{
resolve: "gatsby-plugin-manifest",
options: {
name: "Situs Gatsby",
short_name: "Gatsby",
start_url: "/",
background_color: "#ffffff",
theme_color: "#663399",
display: "standalone",
icon: "src/images/icon.png",
},
},
"gatsby-plugin-offline",
],
}Plugin ordering determines the service worker's behavior: gatsby-plugin-manifest creates the manifest and icon needed before gatsby-plugin-offline assembles the precache from the build's assets.
gatsby-plugin-offline provides two main strategies: precache for assets scanned at build time, and runtime caching for requests that happen after the page loads. Images, fonts, and built pages go into the precache, while external requests that need freshness use a stale-while-revalidate strategy.
The manifest describes the app's name, icons, and behavior when opened full-screen. The configuration in gatsby-plugin-manifest above produces a manifest.webmanifest file linked automatically in the head. Icons must be provided at least at 512x512 to meet the installability criteria.
Browsers show an install prompt when the site has a valid manifest, an active service worker, adequately sized icons, and an HTTPS connection. Once the criteria are met, Android and Chrome users can install the site to the home screen with a standalone appearance.
The offline-first approach structures the UI so it can render without a network, then fills in dynamic data once a connection is available. Gatsby emits complete static HTML, so the page shell still displays even while the user is offline.
For changing data, use IndexedDB so data stays accessible offline:
import { openDB } from "idb"
const db = await openDB("gatsby-cache", 1, {
upgrade(db) {
db.createObjectStore("posts")
},
})
await db.put("posts", data, "latest")openDB from the idb library gives a Promise-based API for IndexedDB. The service worker and IndexedDB work together: the service worker handles assets, IndexedDB handles app data.
Run the PWA category in Lighthouse to verify the installability criteria and the offline experience. Make sure the service worker is registered, the page responds while offline, and all initial assets are precached.
Key takeaways:
gatsby-plugin-offline provides Workbox-based precaching.gatsby-plugin-manifest must be registered before the offline plugin.In the next episode, episode 18, we'll discuss architecture and design patterns — scalable project structure, component-driven design, and patterns for shared components, hooks, and utilities so the site stays maintainable.