Skip to content

Setting Up vite-plugin-pwa

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.

Terminal window
npm install -D vite-plugin-pwa

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,
},
}),
],
});

The registerType option controls how the service worker handles updates when a new version is deployed.

  • 'autoUpdate' — the new SW calls skipWaiting and clients.claim automatically. 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 valueBehaviorWhen to use
autoUpdateSilent background updateApps where staleness is acceptable
promptNew SW waits; user sees a Reload buttonApps where users must see the update

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.

OptionBenefitCost
autoUpdate registerTypeUsers automatically get the new version with no action neededMay reload mid-task if the UX around it is not handled carefully
prompt registerTypeThe user controls when to update, saferYou must build the notification UI yourself, and users may ignore it and stay on the old version for a long time
  • Forgetting to set devOptions.enabled: true and 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 needRefresh state, 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.

Which devDependency installs vite-plugin-pwa?
What does registerType: "autoUpdate" do automatically?
What is the purpose of devOptions: { enabled: true }?
Which option in VitePWA() holds the web app manifest?