Skip to content

PWA with Astro: Overview

Astro is a static-first framework. By default, it builds your site into pure HTML, CSS, and JavaScript — no server required at runtime. That output is exactly what a Progressive Web App needs: a set of cacheable static assets that can be served offline.

The bridge between Astro’s build output and PWA features is @vite-pwa/astro. It is a thin Astro integration that wraps vite-plugin-pwa, which in turn uses Workbox under the hood. When you run astro build, the integration automatically:

  1. Generates a sw.js service worker that precaches your static output.
  2. Creates a manifest.webmanifest that tells browsers your site is installable.
  3. Injects the registration script so the SW activates on first load.

Astro’s islands architecture lets you sprinkle interactive components (React, Preact, Svelte, Vue, Solid…) into an otherwise static page using client:* directives:

src/pages/index.astro
---
import Counter from '../components/Counter.tsx';
---
<h1>Welcome</h1>
<Counter client:visible />

From the service worker’s perspective, islands are just JavaScript files. The SW precaches them alongside your HTML and CSS. When a user goes offline:

  • Static HTML pages are served from the cache instantly.
  • Island JS bundles are also cached, so interactive components hydrate normally.
  • Any client:load, client:visible, or client:idle island works offline as long as its data requirements are met.

@vite-pwa/astro exposes both Workbox strategies:

astro.config.mjs
import { defineConfig } from 'astro/config';
import AstroPWA from '@vite-pwa/astro';
export default defineConfig({
integrations: [
AstroPWA({
// 'generateSW' (default): Workbox writes the SW for you
// 'injectManifest': you write the SW, Workbox injects the precache list
strategies: 'generateSW',
registerType: 'autoUpdate',
}),
],
});

Use generateSW when you want zero-boilerplate offline support. Switch to injectManifest when you need custom fetch logic — for example, a runtime caching strategy for API calls that islands make.

Astro supports both SSG (static site generation, the default) and SSR (server-side rendering via an adapter). PWA support is most natural with SSG:

ModeSW precachingNotes
SSGFull precache of all pages and assetsBest for PWA — everything is known at build time
SSRPrecache only the app shell and static assetsDynamic routes must use runtime caching strategies

This module takes you from zero to a fully offline-capable Astro PWA in five lessons:

LessonWhat you learn
1. Overview (this page)How @vite-pwa/astro works and how it interacts with Astro’s build
2. SetupInstalling and wiring @vite-pwa/astro into a new or existing Astro project
3. Manifest configConfiguring manifest.webmanifest — name, icons, display, theme color
4. SW strategiesChoosing and tuning Workbox caching strategies for pages, assets, and API calls
5. Astro-specific considerationsIslands hydration offline, partial SSR, and edge cases

Each lesson is standalone: skip to any of them at any time.

flowchart LR
  A["Source Files\n(.astro, .tsx, .css)"] -->|"astro build"| B["dist/\n(static HTML + assets)"]
  B --> C["@vite-pwa/astro\n(Workbox)"]
  C --> D["sw.js"]
  C --> E["manifest.webmanifest"]
  D --> F["Browser\n(installs SW, precaches dist/)"]
  E --> F
Astro build → service worker + manifest → browser
Which package does @vite-pwa/astro wrap under the hood?
What does the generateSW strategy do in @vite-pwa/astro?
In an Astro SSG build, what does the service worker precache?
Which Astro output mode is most naturally suited to full PWA precaching?