Service workers

This is Chromium's implementation of service workers. See the Service Worker specification.

Directory structure


Service worker storage consists of the following.

  • Service worker registration metadata is stored in a LevelDB instance located at ${DIR_USER_DATA}/Service Worker/Database.
  • Service worker scripts are stored in a disk_cache instance using the “simple” implementation, located at ${DIR_USER_DATA}/Service Worker/ScriptCache. Registration metadata points to these scripts.

Code pointers include ServiceWorkerDatabase and ServiceWorkerStorage.

The related Cache Storage API uses a disk_cache instance using the “simple” implementation, located at ${DIR_USER_DATA}/Service Worker/CacheStorage. This location was chosen because the Cache Storage API is currently defined in the Service Worker specification, but it can be used independently of service workers.

For incognito windows, everything is in-memory.


Service workers storage lasts indefinitely, i.e, there is no periodic deletion of old but still installed service workers. Installed service workers are only evicted by the Quota Manager (or user action). The Quota Manager controls several web platform APIs, including sandboxed filesystem, WebSQL, appcache, IndexedDB, cache storage, service worker (registration and scripts), and background fetch.

The Quota Manager starts eviction when one of the following conditions is true (as of August 2018):

  • The global pool is full: Chrome is using > 1/3 of the disk (>2/3 on CrOS).
  • The system is critically low on space: the disk has < min(1GB,1%) free (regardless of how much Chrome is contributing!)

When eviction starts, origins are purged on an LRU basis until the triggering condition no longer applies. Purging an origin deletes its storage completely.

Note that Quota Manager eviction is independent of HTTP cache eviction. The HTTP cache is typically much smaller than the storage under the control of the Quota Manager, and it likely uses a simple non-origin-based LRU algorithm.

UseCounter integration

Blink has a UseCounter mechanism intended to measure the percentage of page loads on the web that used a given feature. Service workers complicate this measurement because a feature use in a service worker potentially affects many page loads, including ones in the future.

Therefore, service workers integrate with the UseCounter mechanism as follows:

  • If a feature use occurs before the service worker finished installing, it is recorded in storage along with the service worker. Any page thereafter that the service worker controls is counted as using the feature.
  • If a feature use occurs after the service worker finished installing, all currently controlled pages are counted as using the feature.

For more details and rationale, see Design of UseCounter for workers and crbug 376039.

Code pointers include:


We monitor service worker performance with real-world metrics (UMA) and performance benchmarks.


The UMA data is internal-only. Key metrics include:

Page load metrics for service worker controlled loads:

  • PageLoad.Clients.ServiceWorker2.PaintTiming.NavigationToFirstContentfulPaint
  • PageLoad.Clients.ServiceWorker2.Input.NavigationToFirstContentfulPaint
  • PageLoad.Clients.ServiceWorker2.InteractiveTiming.FirstInputDelay3

Service worker startup time and breakdown:

  • ServiceWorker.StartWorker.Time
  • ServiceWorker.StartTiming.Duration
  • ServiceWorker.StartTiming.*To* (e.g., ServiceWorker.StartTiming.StartToReceivedStartWorker)

Fetch event handling:

  • ServiceWorker.LoadTiming.MainFrame.MainResource.*
  • ServiceWorker.LoadTiming.Subresource.*

TODO(falken, bashi): Add a list of the milestones of startup and fetch event handling.


We run a limited number of Telemetry benchmark tests for service worker. These tests are part of the Loading benchmarks, as the “pwa” tests inside the “” suite. The tests do not run on desktop machines (loading.desktop) due to resource constraints.

See a quick dashboard of these test results. You can also run the benchmarks locally:

# Run benchmark on `FlipKart`
$ tools/perf/run_benchmark --browser=android-chromium --story-filter='FlipKart'

# Run benchmark on `FlipKart` with cache_temperature = cold
$ tools/perf/run_benchmark --browser=android-chromium --story-filter='FlipKart_cold'

TODO(falken): Merge this with and documentation.

The PWA tests load a page multiple times. Each time has a different “cache temperature”. These temperatures have special significance for service worker controlled page loads:

  • cold: tests the very first load to a page (no active service worker). Browser cache and storage data including service worker registrations are cleared first.
  • warm: tests the second load to a page (with an active service worker). It first does a cold load which installs a service worker, waits for the service worker to reach activated state, and then tests the load.
  • hot: tests the third load to the page (with an active service worker and V8 code caching). It first does a warm load, then waits(?) for V8 Code Caching to complete, then tests another load.

Service workers are terminated between loads in order to include service worker startup as part of the performance test.

Code links and resources:

Other documentation