Service Worker Strategies
Service worker strategies
Section titled “Service worker strategies”@vite-pwa/astro gives you two ways to build your service worker: generateSW (the default) and injectManifest. Choosing the right one depends on how much control you need over fetch handling.
generateSW — zero SW code, just config
Section titled “generateSW — zero SW code, just config”With generateSW, Vite PWA writes the entire service worker for you. You provide a configuration object under the workbox key and Workbox generates sw.js at build time. This is the right choice for the vast majority of Astro sites: precaching the static build output plus a handful of runtime caching rules cover most real-world requirements with no service worker code to maintain.
Set registerType: 'autoUpdate' to let the new service worker install and activate silently whenever you ship an update. Users always get the latest version without seeing any prompt.
AstroPWA({ registerType: 'autoUpdate', workbox: { globPatterns: ['**/*.{css,js,html,svg,png,ico,txt,woff2}'], runtimeCaching: [ { urlPattern: /^https:\/\/fonts\.googleapis\.com\/.*/i, handler: 'CacheFirst', options: { cacheName: 'google-fonts-cache', expiration: { maxEntries: 10, maxAgeSeconds: 60 * 60 * 24 * 365 }, }, }, { urlPattern: /^https:\/\/api\.example\.com\/.*/i, handler: 'NetworkFirst', options: { cacheName: 'api-cache', networkTimeoutSeconds: 5 }, }, ], },})globPatterns defines which built files are added to the precache manifest — these are downloaded on install and served from cache on every subsequent visit, even offline. The runtimeCaching array adds caching rules that kick in at fetch time for URLs that match each pattern. CacheFirst is ideal for immutable assets like fonts; NetworkFirst is the right choice for API endpoints where freshness matters.
injectManifest — you control the SW
Section titled “injectManifest — you control the SW”When you need custom fetch logic — advanced routing, background sync, push notifications, or anything Workbox’s automatic generation cannot express — switch to injectManifest. You write your own src/sw.ts; at build time Vite PWA compiles it and injects the precache manifest into it via the self.__WB_MANIFEST placeholder.
AstroPWA({ strategies: 'injectManifest', srcDir: 'src', filename: 'sw.ts',})// src/sw.ts (your custom service worker)import { cleanupOutdatedCaches, precacheAndRoute } from 'workbox-precaching'
declare let self: ServiceWorkerGlobalScope
cleanupOutdatedCaches()precacheAndRoute(self.__WB_MANIFEST)
self.addEventListener('fetch', (event) => { // your custom fetch logic here})precacheAndRoute(self.__WB_MANIFEST) replaces the placeholder with the real manifest list at build time, giving you automatic precaching alongside whatever custom fetch handling you add.
virtual:pwa-register and the prompt flow
Section titled “virtual:pwa-register and the prompt flow”When registerType is 'prompt', the service worker waits for your code to trigger the update. Import registerSW from the virtual module virtual:pwa-register to wire up the confirmation UI:
import { registerSW } from 'virtual:pwa-register'
const updateSW = registerSW({ onNeedRefresh() { if (confirm('New content available. Reload?')) { updateSW(true) } }, onOfflineReady() { console.log('App ready to work offline') },})<script> import './pwa.ts'</script>Add <PwaInit /> to your root layout so the registration logic runs on every page. With autoUpdate you can skip this entirely — nothing calls updateSW(true) because the update is applied automatically.
flowchart TD A[Need custom SW logic?] -->|No| B[generateSW] A -->|Yes| C[injectManifest] B --> D[Workbox generates sw.js automatically] C --> E[You write src/sw.ts with workbox-precaching] D --> F[Configure via workbox: options] E --> G[Full control over fetch handling]
Trade-offs
Section titled “Trade-offs”| Option | Benefit | Cost |
|---|---|---|
generateSW (Workbox generates it automatically) | Fastest to get started, no service worker to write yourself | Less room for custom logic than writing it by hand |
injectManifest (write the SW yourself, inject the precache list) | Full control over the logic, freely mix in custom behavior | You write and maintain the service worker file yourself, adding complexity |
Common mistakes
Section titled “Common mistakes”- Choosing
generateSWand then trying to add custom logic the mode does not support, forcing a later migration toinjectManifestand wasted refactor time. - Not matching the strategy to the route type in Astro (static page vs. API endpoint), so the wrong kind of caching gets applied.
- Forgetting that Astro’s build output changes asset hashes on every build, so an old generated precache manifest no longer matches the real files if you do not rebuild.
The @vite-pwa/astro ecosystem offers both modes; most documentation projects use generateSW because it is enough for a static site, while apps with complex custom offline logic choose injectManifest to mix a custom fetch handler with the precache list Workbox generates.