API in Service Worker
Service Worker Static Routing API
Published Updated
The Service Worker Static Routing API lets a service worker declare, at install time, which
requests the browser should serve from the network or from a cache without running the
worker to fetch them. The declaration is a list of rules passed to event.addRoutes() in
the install handler, and each rule pairs a condition on the request with the source the
response should come from.
Syntax
Section titled “Syntax”addRoutes(routerRules)routerRules is a single rule object or an array of them, and the method returns a promise
that fulfills with undefined. The method is on InstallEvent, so it is reachable from the
install handler, and a rule set therefore belongs to the worker version that installed it.
The specification notes that event.addRoutes(rules) extends the lifetime of the event by
default, as if event.waitUntil(promise) had been called.
Support by engine
Section titled “Support by engine”BCD api.InstallEvent.addRoutes records support from Chrome 123 and Safari 27, mirrored
into the Chromium-based browsers and the Safari derivatives it lists, and no support in
Firefox, where it points at Mozilla bug 1855580 for the
implementation status. Chrome’s launch post describes the API as available from Chrome 123
after an origin trial that began in Chrome 116 under the name registerRouter(), a method
the post marks deprecated with removal planned for Chrome 125.
Parameters
Section titled “Parameters”A rule is { condition, source }. The condition keys below are the ones MDN’s
addRoutes() reference
documents; when several are present in one condition, a resource must meet all of them to
match the rule.
| Condition key | Value | Matches |
|---|---|---|
urlPattern |
a URLPattern instance, or a constructor input pattern |
the URLs that match the rule. Regular expression capturing groups are not allowed, so URLPattern.hasRegExpGroups has to be false. |
requestMethod |
string, such as "get", "put" or "head" |
the HTTP method the request is sent by. |
requestMode |
string, such as "same-origin", "no-cors" or "cors" |
the mode the request has. |
requestDestination |
string, such as "audio", "document", "script" or "worker" |
the destination of the request, that is, the content type requested. |
runningStatus |
"running" or "not-running" |
the required running status of the service worker. |
or |
an array of condition objects | one set of the nested conditions. Conditions inside or are mutually exclusive with other conditions. |
not |
a condition object | conditions that must explicitly not be met. Conditions inside not are mutually exclusive with other conditions. |
source is an enumerated value or an object. MDN’s enumerated values are "cache",
"network", "fetch-event" and "race-network-and-fetch-handler", the last of which
attempts the network and the fetch event handler simultaneously and uses whichever
completes first. MDN pairs "fetch-event" with the runningStatus condition to load a
resource through the worker while it is running and fall back to a static route on the
network while it is not. The object form carries a single cacheName property naming a
cache; MDN notes that if that cache does not exist the browser defaults to the network so
the requested resources can still be obtained when the network is available.
Exceptions
Section titled “Exceptions”MDN lists these causes for a TypeError: a rule object inside routerRules that is
invalid, a source of "fetch-event" on a worker with no fetch event handler, and or
combined with another condition type.
- An invalid rule rejects the call that carried it, so validate a generated rule list before shipping it.
"fetch-event"and"race-network-and-fetch-handler"depend on a registeredfetchhandler. TheaddRoutes()algorithm returns a promise rejected with aTypeErrorwhensourceis either"fetch-event"or"race-network-and-fetch-handler"and the service worker’s set of event types to handle does not containfetch. Rules whosesourceis"network","cache"or thecacheNameobject are not named by that step.- A condition that carries
ornext to a sibling key has to be rewritten as two rules, one per branch, each repeating the sibling. MDN’s own example of that rewrite pairsurlPatternwithrequestMethodtwice. - The specification also rejects the promise with a
TypeErrorwhen the Check Router Registration Limit algorithm, run over a copy of the worker’s existing list of router rules with the new rules appended, returns false.
An empty condition object is a rejection rather than a rule matching everything, which is the first string above.
Examples
Section titled “Examples”The examples below are the shapes most apps need: bypass the worker on a path, declare routes where the method exists, and serve image extensions from a named cache.
Sending a path to the network when the worker is cold
Section titled “Sending a path to the network when the worker is cold”The condition combines a URL pattern with runningStatus, so the rule applies while the
service worker is not running, which is the case that costs a start-up.
addEventListener('install', (event) => { event.addRoutes({ condition: { urlPattern: '/articles/*', runningStatus: 'not-running', }, source: 'network', });});While the worker is running this rule does not match, and the request reaches the fetch
handler, so a cache-first strategy for the same path still applies on warm navigations.
Chrome’s launch post shows the mirror-image rule, runningStatus: "running" with
source: "fetch-event".
Declaring routes where the method exists, with a fallback
Section titled “Declaring routes where the method exists, with a fallback”addRoutes() is a method on the event object, so it can be tested before use. The absent
branch is not a degraded mode: it is the behaviour a service worker had before static
routes, where the fetch handler decides everything.
addEventListener('install', (event) => { if (!('addRoutes' in event)) { // No addRoutes() on this event: leave the routing to the fetch handler. return; } event .addRoutes([ { condition: { urlPattern: '/form/*', requestMethod: 'post' }, source: 'network' }, { condition: { requestDestination: 'font' }, source: { cacheName: 'fonts' } }, ]) .catch((error) => { console.error('static routes rejected, using the fetch handler instead', error); });});Keep the catch. The method reports its failures by rejecting rather than throwing
synchronously, so a rejection with no handler leaves the app running on the fetch handler
alone and surfaces as an unhandled promise rejection.
Serving two image extensions from one named cache
Section titled “Serving two image extensions from one named cache”or takes a list of conditions and is mutually exclusive with other conditions, so the
extensions go inside the array and the shared source stays outside it.
addEventListener('install', (event) => { event.addRoutes({ condition: { or: [{ urlPattern: '*.png' }, { urlPattern: '*.jpg' }], }, source: { cacheName: 'pictures' }, });});To narrow the same two patterns to GET requests, write two rules, each with its own
urlPattern and requestMethod, which is the rewrite MDN gives for this case.
Chrome DevTools shows what the browser registered: Chrome’s launch post states that registered router rules are displayed in the Service Worker tab of the Application panel, and that in the Network panel a request matching a registered rule is indicated in the size column, with the registered router ID shown on pointer hover.
See also
Section titled “See also”- FetchEvent and request routing
- Caching strategies for service workers
- NavigationPreloadManager
- Service worker lifecycle
- InstallEvent: addRoutes() method (developer.mozilla.org)
- Service Workers: the addRoutes() method (w3c.github.io)
- Use the Service Worker Static Routing API to bypass the service worker for specific paths (developer.chrome.com)
Specifications
| Specification | Status |
|---|---|
| Service Workers: the addRoutes() method | W3C draft |