Astro-Specific Considerations
Astro-specific considerations for PWAs
Section titled “Astro-specific considerations for PWAs”Astro’s flexibility — static, SSR, or hybrid rendering — introduces a handful of decisions that directly affect how your service worker behaves. Getting these right means your users enjoy a fast, reliable offline experience without stale or missing responses.
SSG vs SSR/hybrid: what gets precached
Section titled “SSG vs SSR/hybrid: what gets precached”Astro’s default output mode is static. Every page is rendered to an .html file at build time, so @vite-pwa/astro can walk the dist/ folder and include every HTML file in the precache manifest automatically.
Switch to output: 'server' or output: 'hybrid' and the picture changes: SSR routes are generated on the server at request time, so there is no .html file for Workbox to hash and precache. Those routes must be handled by runtime caching instead.
// astro.config.mjs — SSG (default), all pages precachedAstroPWA({ registerType: 'autoUpdate', workbox: { globPatterns: ['**/*.{css,js,html,svg,png,ico}'], // Every /blog/*, /about, / etc. is a static file — precached },})// astro.config.mjs — hybrid SSR// output: 'hybrid' or 'server'AstroPWA({ registerType: 'autoUpdate', workbox: { globPatterns: ['**/*.{css,js,svg,png,ico}'], // assets only — no .html for SSR routes runtimeCaching: [ { urlPattern: ({ url }) => url.pathname.startsWith('/api/'), handler: 'NetworkFirst', options: { cacheName: 'api-cache', networkTimeoutSeconds: 3 }, }, ], },})Quick reference
Section titled “Quick reference”| Scenario | Precache | Runtime cache |
|---|---|---|
SSG page (output: 'static') | Yes (auto) | Optional |
SSR page (output: 'server') | No | Required |
| Static asset (CSS/JS/images) | Yes | No |
| External API | No | Required |
Base path and scope alignment
Section titled “Base path and scope alignment”When you deploy Astro to a sub-path (for example, GitHub Pages at /my-app/), the service worker scope must match that base. If the scope is / but your app lives at /my-app/, the SW will fail to control your pages.
Set base, scope, manifest.start_url, and the Workbox globPatterns root together:
// astro.config.mjs — deployed at /my-app/export default defineConfig({ base: '/my-app/', integrations: [ AstroPWA({ scope: '/my-app/', base: '/my-app/', manifest: { start_url: '/my-app/' }, workbox: { globPatterns: ['**/*.{css,js,html,svg,png,ico}'] }, }), ],})Astro’s default trailingSlash is 'ignore', which means both /about and /about/ are valid. Make sure your scope ends with a slash (/my-app/) so the SW controls all paths under that prefix.
Islands hydration and offline behavior
Section titled “Islands hydration and offline behavior”Astro islands ship each component’s JavaScript as a separate chunk in dist/. Because @vite-pwa/astro precaches every file matching globPatterns, all island JS bundles are cached automatically. An island using client:visible or client:idle will hydrate correctly offline as long as its chunk is in the precache manifest — which it will be if your globPatterns includes **/*.js.
No extra configuration is needed for islands offline support. The key constraint is that the island’s data must also be available offline: if the component fetches from an uncached API at runtime, that data will be missing.
Testing with astro preview
Section titled “Testing with astro preview”The service worker is only generated during astro build. Running astro dev does not produce a SW, so DevTools will show no service worker registered. Always test your PWA against the production build:
# Build first, then preview — the SW only works in the built outputnpm run buildnpm run preview# Open http://localhost:4321 in DevTools > Application > Service WorkersAfter opening the preview URL, navigate to DevTools → Application → Service Workers to confirm the SW is registered and active. Use Cache Storage to verify that your precache manifest entries are present. To simulate offline behavior, check the Offline checkbox in the Network panel and reload.