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

> Easily add PWA functionality to your Docusaurus site. Learn to implement offline mode and enhance user experience with the `@docusaurus/plugin-pwa` package. Get started today!

- Repository: [Meta/docusaurus](https://github.com/facebook/docusaurus)
- Tags: how-to-guide
- Published: 2026-03-04

---

**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`](https://github.com/facebook/docusaurus/blob/main/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.

```bash
yarn add @docusaurus/plugin-pwa

# or

npm install @docusaurus/plugin-pwa

```

Once installed, register the plugin in your [`docusaurus.config.js`](https://github.com/facebook/docusaurus/blob/main/docusaurus.config.js) file. The plugin accepts a configuration object that defines offline behavior, debug settings, and head tag injection.

```javascript
// 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`](https://github.com/facebook/docusaurus/blob/main/options.ts)** — Defines the configuration schema and default values for `offlineModeActivationStrategies`, `injectManifestConfig`, and `pwaHead`. This file validates your [`docusaurus.config.js`](https://github.com/facebook/docusaurus/blob/main/docusaurus.config.js) options at build time.
- **[`registerSw.ts`](https://github.com/facebook/docusaurus/blob/main/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`](https://github.com/facebook/docusaurus/blob/main/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`](https://github.com/facebook/docusaurus/blob/main/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`](https://github.com/facebook/docusaurus/blob/main/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`](https://github.com/facebook/docusaurus/blob/main/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:

```javascript
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:

```json
// 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.

```javascript
// docusaurus.config.js
{
  swCustom: require.resolve('./src/custom-sw.js'),
}

```

```javascript
// 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:

```bash
npx docusaurus swizzle @docusaurus/theme-classic PwaReloadPopup

```

This copies the component to [`src/theme/PwaReloadPopup/index.tsx`](https://github.com/facebook/docusaurus/blob/main/src/theme/PwaReloadPopup/index.tsx) where you can modify the JSX and styling:

```tsx
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`](https://github.com/facebook/docusaurus/blob/main/renderReloadPopup.tsx).

### Fine-Tuning Precaching with Workbox

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

```javascript
{
  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`](https://github.com/facebook/docusaurus/blob/main/docusaurus.config.js).
- **Configure activation strategies** like `appInstalled`, `standalone`, or `always` to control when offline mode activates based on the logic in [`registerSw.ts`](https://github.com/facebook/docusaurus/blob/main/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`](https://github.com/facebook/docusaurus/blob/main/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`](https://github.com/facebook/docusaurus/blob/main/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`](https://github.com/facebook/docusaurus/blob/main/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.