Setting Up vite-plugin-pwa
Introduction
Section titled “Introduction”vite-plugin-pwa is the standard way to add PWA support to a Vite-based React app. One plugin call in vite.config.ts handles service worker generation, manifest injection, and asset precaching. You configure everything in one place and Workbox does the heavy lifting at build time.
Install
Section titled “Install”npm install -D vite-plugin-pwaBasic configuration
Section titled “Basic configuration”Add VitePWA to your Vite plugins array in vite.config.ts:
import { defineConfig } from 'vite';import react from '@vitejs/plugin-react';import { VitePWA } from 'vite-plugin-pwa';
export default defineConfig({ plugins: [ react(), VitePWA({ registerType: 'autoUpdate', includeAssets: ['favicon.ico', 'apple-touch-icon.png', 'mask-icon.svg'], manifest: { name: 'My React PWA', short_name: 'ReactPWA', description: 'A progressive web app built with Vite and React', theme_color: '#ffffff', icons: [ { src: 'pwa-192x192.png', sizes: '192x192', type: 'image/png', }, { src: 'pwa-512x512.png', sizes: '512x512', type: 'image/png', }, ], }, devOptions: { enabled: true, }, }), ],});registerType
Section titled “registerType”The registerType option controls how the service worker handles updates when a new version is deployed.
'autoUpdate'— the new SW callsskipWaitingandclients.claimautomatically. The page is updated silently in the background without any user interaction. This is appropriate when stale content for a short period is acceptable.'prompt'— the new SW installs but waits. Your app code is responsible for detecting the waiting SW and showing a UI element (such as a Reload button) that lets the user decide when to refresh.
| registerType value | Behavior | When to use |
|---|---|---|
| autoUpdate | Silent background update | Apps where staleness is acceptable |
| prompt | New SW waits; user sees a Reload button | Apps where users must see the update |
devOptions
Section titled “devOptions”devOptions: { enabled: true } activates the service worker in Vite’s development server so you can test caching and offline behavior locally. Set it to false or omit the field entirely in production CI pipelines where you do not want a SW interfering with the build output checks.
Trade-offs
Section titled “Trade-offs”| Option | Benefit | Cost |
|---|---|---|
autoUpdate registerType | Users automatically get the new version with no action needed | May reload mid-task if the UX around it is not handled carefully |
prompt registerType | The user controls when to update, safer | You must build the notification UI yourself, and users may ignore it and stay on the old version for a long time |
Common mistakes
Section titled “Common mistakes”- Forgetting to set
devOptions.enabled: trueand being confused about why the service worker does nothing in dev mode (it is off by default). - Testing PWA behavior on
npm run dev, assuming it behaves like production, when the service worker actually works differently there — always test against a real build. - Not building UI for the
needRefreshstate, so the user never finds out a new version is available.
The Vite PWA ecosystem is a standard plugin that real projects like Elk (the Mastodon client) use to build a full PWA on Vite/React, and many VitePress sites use the same vite-plugin-pwa setup to turn thousands of documentation sites into installable PWAs with little effort.