The $service-worker Module
Vanilla SvelteKit service workers
Section titled “Vanilla SvelteKit service workers”SvelteKit automatically bundles and registers any file you place at src/service-worker.js (or .ts). Inside that file, the $service-worker virtual module gives you everything you need to write a robust precaching service worker without any third-party library.
What $service-worker exports
Section titled “What $service-worker exports”| Export | Type | Contents |
|---|---|---|
build | string[] | Hashed client-side assets (_app/immutable/…) |
files | string[] | Everything copied from static/ |
version | string | Unique string that changes on every build |
prerendered | string[] | Paths of prerendered HTML pages |
build and files together cover the full set of assets your app needs to work offline. version makes a unique cache name so old caches are cleaned up reliably after each deploy.
Creating src/service-worker.js
Section titled “Creating src/service-worker.js”/// <reference types="@sveltejs/kit" />import { build, files, version, prerendered } from '$service-worker';
const CACHE = `cache-\${version}`;
const ASSETS = [ ...build, // hashed JS/CSS bundles ...files, // static/ assets (icons, fonts, …) ...prerendered, // prerendered HTML pages];
// -- Install: precache all assets ----------------------------------------------self.addEventListener('install', (event) => { async function addFilesToCache() { const cache = await caches.open(CACHE); await cache.addAll(ASSETS); } event.waitUntil(addFilesToCache());});
// -- Activate: delete old caches -----------------------------------------------self.addEventListener('activate', (event) => { async function deleteOldCaches() { for (const key of await caches.keys()) { if (key !== CACHE) await caches.delete(key); } } event.waitUntil(deleteOldCaches());});
// -- Fetch: serve from cache, fall back to network -----------------------------self.addEventListener('fetch', (event) => { if (event.request.method !== 'GET') return;
async function respond() { const url = new URL(event.request.url); const cache = await caches.open(CACHE);
// Always serve build/files assets from cache (they are hashed) if (ASSETS.includes(url.pathname)) { const cached = await cache.match(url.pathname); if (cached) return cached; }
// For everything else: network first, cache as fallback try { const response = await fetch(event.request); if (response.status === 200) { cache.put(event.request, response.clone()); } return response; } catch { const cached = await cache.match(event.request); if (cached) return cached; throw new Error('No cached response and network unavailable'); } }
event.respondWith(respond());});Why the cache name uses version
Section titled “Why the cache name uses version”Every SvelteKit build produces a fresh version string derived from the build timestamp and content hash. The pattern `cache-\${version}` means each deployment gets its own isolated cache. The activate handler then deletes every cache whose name is not the current version — automatically cleaning up storage from all previous deploys.
TypeScript version
Section titled “TypeScript version”For TypeScript projects, rename the file to src/service-worker.ts and add the reference directive so the SW globals are typed correctly:
/// <reference types="@sveltejs/kit" />import { build, files, version, prerendered } from '$service-worker';
declare const self: ServiceWorkerGlobalScope;
const CACHE = `cache-\${version}`;// … rest of the file is identicalWhat about prerendered?
Section titled “What about prerendered?”If your app prerender pages (via export const prerender = true in route files or adapter-static), SvelteKit populates prerendered with their paths. Including them in ASSETS means those pages load instantly offline, without a network round-trip.
Trade-offs
Section titled “Trade-offs”| Option | Benefit | Cost |
|---|---|---|
Use SvelteKit’s $service-worker module | Direct access to the build manifest (asset list, version) straight from SvelteKit itself | Tied to a SvelteKit-specific convention — moving to another framework means rewriting it |
| Write a static service worker without relying on the SvelteKit module | Works even outside the SvelteKit build pipeline | You maintain the asset list yourself instead of letting the framework generate it |
Common mistakes
Section titled “Common mistakes”- Importing
$service-workerin the wrong context (outside the service worker file), causing a build error because the module only resolves when building the service worker. - Not using the
buildandfilesexports from this module for precaching, forcing you to list assets by hand and fall out of sync with the real build. - Forgetting that
versionfrom this module changes on every build, so if you do not use it in the cache name, old caches get invalidated at the wrong time.
The SvelteKit official service worker docs present $service-worker as the standard approach for every SvelteKit project that needs build-aware precaching, and many projects built on SvelteKit extend this same module to build an offline-first app.