How to Set Up PWA Functionality with the Docusaurus PWA Plugin: Complete Implementation Guide

The @docusaurus/plugin-pwa package transforms any Docusaurus site into a Progressive Web App by injecting PWA head tags, registering a Workbox-based service worker, and implementing configurable offline mode activation strategies.

The facebook/docusaurus repository maintains the official PWA plugin that enables offline documentation browsing and installable app experiences. By configuring the plugin in docusaurus.config.js, you enable service worker precaching, custom activation logic, and PWA-compliant manifest injection without writing boilerplate service worker code.

Installing the Docusaurus PWA Plugin

Add the plugin to your project using your package manager of choice.

yarn add @docusaurus/plugin-pwa

# or

npm install @docusaurus/plugin-pwa

Once installed, register the plugin in your docusaurus.config.js file. The plugin accepts a configuration object that defines offline behavior, debug settings, and head tag injection.

// docusaurus.config.js
module.exports = {
  // ... existing config
  plugins: [
    [
      '@docusaurus/plugin-pwa',
      {
        debug: false,
        offlineModeActivationStrategies: [
          'appInstalled',
          'standalone',
          'queryString',
        ],
        pwaHead: [
          {
            tagName: 'link',
            rel: 'manifest',
            href: '/manifest.webmanifest',
          },
          {
            tagName: 'meta',
            name: 'theme-color',
            content: '#0d47a1',
          },
        ],
      },
    ],
  ],
};

Core Architecture and Source Files

The plugin architecture consists of five key components implemented in packages/docusaurus-plugin-pwa/src/:

  • options.ts — Defines the configuration schema and default values for offlineModeActivationStrategies, injectManifestConfig, and pwaHead. This file validates your docusaurus.config.js options at build time.
  • registerSw.ts — Runs in the browser to register the service worker using workbox-window. It reads environment variables (PWA_SERVICE_WORKER_URL, PWA_OFFLINE_MODE_ACTIVATION_STRATEGIES, PWA_DEBUG) to determine when to activate offline mode.
  • sw.ts — The actual service worker implementation that uses workbox-precaching to cache assets. It handles install, activate, fetch, and message events, and executes custom logic from swCustom if provided.
  • renderReloadPopup.tsx — Dynamically imports and renders the PwaReloadPopup component when a new service worker is waiting, prompting users to reload for updates.
  • plugin-pwa.d.ts — Provides TypeScript type definitions for PluginOptions and configuration interfaces.

Offline Mode Activation Strategies

The plugin supports seven activation strategies defined in options.ts. When any enabled strategy returns true, the service worker precaches assets and enables offline functionality.

Strategy Activation Condition
appInstalled Site is installed as a PWA (detected via appinstalled event or navigator.getInstalledRelatedApps).
standalone Page runs in standalone display mode (window.matchMedia('(display-mode: standalone)')).
queryString URL contains ?offlineMode=true for debugging purposes.
mobile Browser viewport width is ≤ 996 pixels.
saveData User's connection has the saveData flag enabled.
always Unconditionally enables offline mode.
Default combination By default, the plugin uses appInstalled, queryString, and standalone.

Configure these in your plugin options array:

offlineModeActivationStrategies: ['standalone', 'appInstalled', 'mobile']

Creating the Web App Manifest

While optional, a Web App Manifest is required for installable PWA functionality. Create a manifest.webmanifest file in your static directory:

// static/manifest.webmanifest
{
  "name": "My Docusaurus Site",
  "short_name": "Docs",
  "start_url": ".",
  "display": "standalone",
  "background_color": "#ffffff",
  "theme_color": "#ffffff",
  "icons": [
    {
      "src": "/img/logo.png",
      "sizes": "512x512",
      "type": "image/png"
    }
  ]
}

Reference this manifest in your pwaHead configuration using the tagName: 'link' with rel: 'manifest' as shown in the configuration example above.

Advanced Customization

Custom Service Worker Logic

For additional caching rules or background sync, provide a custom service worker file via the swCustom option. The plugin imports your default export and invokes it with {offlineMode, debug} parameters.

// docusaurus.config.js
{
  swCustom: require.resolve('./src/custom-sw.js'),
}
// src/custom-sw.js
export default function ({offlineMode, debug}) {
  if (debug) {
    console.log('[CustomSW] Running with offlineMode:', offlineMode);
  }
  
  if (offlineMode) {
    self.addEventListener('fetch', (event) => {
      if (event.request.url.includes('/api/')) {
        event.respondWith(
          caches.match(event.request).then((response) => {
            return response || fetch(event.request);
          }),
        );
      }
    });
  }
}

Customizing the Reload Popup

Override the default update notification UI by swizzling the theme component:

npx docusaurus swizzle @docusaurus/theme-classic PwaReloadPopup

This copies the component to src/theme/PwaReloadPopup/index.tsx where you can modify the JSX and styling:

import React from 'react';
import Translate from '@docusaurus/Translate';
import styles from './styles.module.css';

export default function PwaReloadPopup({onReload}) {
  return (
    <div className={styles.popup}>
      <p>
        <Translate id="pwa.reloadMessage">
          A new version is available.
        </Translate>
      </p>
      <button onClick={onReload}>
        <Translate id="pwa.reloadButton">Update Now</Translate>
      </button>
    </div>
  );
}

The plugin automatically detects and uses your swizzled component through renderReloadPopup.tsx.

Fine-Tuning Precaching with Workbox

Control precaching behavior through injectManifestConfig, which accepts standard Workbox InjectManifest options:

{
  injectManifestConfig: {
    maximumFileSizeToCacheInBytes: 5 * 1024 * 1024, // 5MB
    exclude: [/\.map$/, /admin\//],
  },
}

Summary

  • Install the plugin via yarn add @docusaurus/plugin-pwa and register it in docusaurus.config.js.
  • Configure activation strategies like appInstalled, standalone, or always to control when offline mode activates based on the logic in registerSw.ts.
  • Provide PWA head tags including manifest links and theme colors to satisfy PWA requirements.
  • Customize behavior by pointing swCustom to a JavaScript file for additional service worker logic, or swizzle PwaReloadPopup to change the update UI.
  • Verify functionality using Chrome DevTools Application panel to inspect the service worker registration and cached assets.

Frequently Asked Questions

What does the Docusaurus PWA plugin do?

The plugin converts your static Docusaurus site into a Progressive Web App by generating a service worker (via sw.ts) that precaches build assets, injecting required <meta> and <link> tags into the document head, and managing offline mode activation through configurable strategies defined in options.ts.

How do I enable offline mode in Docusaurus?

Offline mode is controlled by the offlineModeActivationStrategies array in your plugin configuration. Set this to ['always'] to enable it unconditionally, or use conditional strategies like 'appInstalled' or 'standalone' to activate only when the user has installed the PWA or is running it as a standalone app.

Can I customize the service worker in Docusaurus PWA?

Yes. Use the swCustom configuration option to point to a JavaScript file exporting a default function. The plugin executes this function inside the service worker context with offlineMode and debug parameters, allowing you to add custom fetch handlers, background sync, or additional caching logic alongside the default Workbox precaching.

How do I test if my Docusaurus PWA is working correctly?

Run yarn start or yarn build followed by yarn serve to test the production build. Open Chrome DevTools, navigate to Application > Service Workers, and verify that sw.js is registered. Check the Cache Storage section for precached assets, and use the Network panel to simulate offline mode to confirm that pages load without a connection.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →