Resource Caching

Developers can build more resilient and user-friendly web applications that perform reliably under various network conditions. Also, it is possible to warm cache a selection of resources. This is powerfull as it allows applications to partially work offline.

The default strategy applied for resources is Network First i.e. the resource from the web server is fetched first. In case of failure, the cached data is served. By default, the service worker will wait 3 seconds before serving the cached version. This value can be configured.

        enabled: true
        src: "sw.js"
                - match_callback: 'startsWith: /pages/'
                  cache_name: 'static-pages'
                  strategy: 'NetworkFirst'
                  network_timeout: 2 # Wait only 2 seconds (only when strategy is networkFirst or NetworkOnly)
                - match_callback: 'regex: \/articles\/.*$'
                  cache_name: 'articles'
                  strategy: 'StaleWhileRevalidate'
                  broadcast: true # Broadcast changes only when strategy = staleWhileRevalidate

Please note that you can refer to any URLs, but only URLs served by your application will be cached.

Match Callback

The match_callback option is designed to specify the condition used to determine which requests should be cached based on the request URL. This option can take different types of values, such as

  • A regular expression

  • A Javasrcipt callback

  • A prefixed statement

Regular Expression

You can directly pass a regular expression as a string or using the JS RegExp object.

  • match_callback: '"/styles/.*\.css"'

  • match_callback: 'new RegExp("/styles/.*\.css")'

Quotes are important!

Javascript Callback

Workbox gives you the url, the params, the request and the event objects. You can use any of those parameters to match with your cache.

  • match_callback: '({url}) => url.pathname === "/special/url"'

  • match_callback: '({request}) => request.destination === "image"'

Quotes are important!

Prefixed Statements

This bundle allows the use of handlers to avoid the use of JS and simplify the way you declare the callbacks.

For instance, using startsWith: /pages/ as the match_callback value means that any request URL that begins with /pages/ will be considered a match and thus eligible for caching under the defined cache_name.

Or destination: image is identical to match_callback: '({request}) => request.destination === "image"'.

This approach empowers developers to optimize their web application's performance by strategically caching resources based on URL patterns, ensuring that users enjoy faster load times and a smoother overall experience, even in offline scenarios or under suboptimal network conditions.

Provided Match Callback Handlers:



Matches all resources the user navigates to.

No example. This is an exact match


Matches a certain type of resource. Available values are listed on the Request object documentation.

  • destination: audio

  • destination: style

  • destination: video


Matches the exact Symfony route. Shall not have required parameters

  • route: app_homepage

  • route: app_princing


Matches an exact pathname

  • pathname: /foo/bar.docx

  • pathname: /report.pdf


Matches all requests to the origin

  • origin:

  • origin:


Matches all pathnames starting with the value

  • startsWith: /dashboard

  • startsWith: /admin


Matches all pathnames ending with the value

  • endsWith: .css

  • endsWith: -report.pdf

Custom Match Callback Handler

If needed, you can create your own Match Callback Handler. It must implement SpomkyLabs\PwaBundle\MatchCallbackHandler\MatchCallbackHandler and should return a value compatible with the capture argument of the Workbox method registerRoute.

In the following example, setting match_callback: my-videos is a simplified way to match only videos served from a specific origin.



use SpomkyLabs\PwaBundle\MatchCallbackHandler\MatchCallbackHandler;

namespace Acme\MatchCallbackHandler;

final readonly class MyVideosMatchCallbackHandler implements MatchCallbackHandler
    public function supports(string $matchCallback): bool
        return $matchCallback === 'my-videos';

    public function handle(string $matchCallback): string
        return sprintf("({url, request}) => (url.origin === '' && request.destination === 'video');

The class shall be declared as a service.

Cache Name Parameter

The cache_name parameter is used to customize the cache name. If not set, a default value is defined.

Strategy Parameter

The strategy option corresponds to the Workbox strategy.

CacheFirst (Cache Falling Back to Network)

This strategy serves responses from the cache first, falling back to the network if the requested resource is not in the cache. It is ideal for assets that do not update frequently.

NetworkFirst (Network Falling Back to Cache)

The reverse of Cache First, this strategy tries to fetch the response from the network first. If the request fails (e.g., due to being offline), it falls back to the cache. Suitable for content where freshness is more critical.


This strategy serves cached responses immediately while silently fetching an updated version from the network in the background for future use. It is a good compromise for resources that need to be updated occasionally without compromising the user experience with loading delays.


A strategy that only uses the network, not attempting to cache or match responses from the cache. This is useful for non-cachable responses such as API requests returning user-specific data.


Conversely, the Cache Only strategy serves responses from the cache, ignoring the network. This is ideal for offline applications where you want to ensure that only cached resources are served.

Leveraging Workbox strategies allows you to fine-tune how your application handles caching, ensuring that your users get the best possible experience whether they are online or offline.

Network Timeout

The Workbox network_timeout option indicates the number of seconds before the request falls back to the strategy. It is only available with NetworkFirst and NetworkOnly.

Max Entries / Max Age

When set, this indicates the expiration strategy used for the resource cache. max_age can be in seconds or a human-readable string

max_age: 3600 and max_age: 1 hour are similar.

max_entries is a positive number. When the cache reaches the number of cached resources, old resources are removed.

Range Requests

When making a request, a range header can be set that tells the server to return only a portion of the full request. This is useful for certain files like a video file, where a user might change where to play the video.

By setting the range_requests: true, this type of requests will be supported.

Broadcast Parameter

When accessing a page with the StaleWhileRevalidate strategy, the Service Worker will verify if a page update exists and will save it in the cache if any.

The broadcast parameter will tell the Service Worker to send a broadcast message in case of an update. This is usefull to warn the user it is reading an outdated version of the page and ask for a page reload.

In the example below, the message is catched and, if it is of type "workbox-broadcast-update" and the URL matches with the current URL, a toast notification is displayed for 5 seconds.

navigator.serviceWorker.addEventListener('message', async event => {
    if ( === 'workbox-broadcast-update') {
        const {updatedURL} =;
        if (updatedURL === window.location.href) {
            const toast = document.getElementById('toast-refresh');
            setTimeout(() => {
            }, 5000);

Broadcast Header

By default, the page header used to check if the page is outdated or not are Content-Length, ETag, Last-Modified. These headers can be changed.

                - ...
                      - 'X-App-Cache'

Cacheable Responses

By default, all responses with a 0 or 200 status code and that match with the match_callback option will be cached. It is possible to tell Workbox to cache only resources with a dedicated header or other status codes:

        enabled: true
        src: "sw.js"
                - match_callback: 'startsWith: /pages/'
                    'X-Is-Cacheable': 'true'
                  cacheable_response_statuses: [200]

URL Preload

The resource caching allows URLs to be preloaded. The accepted values are URLs as defined in the Shorcut page.

You can also set asset URLs like audio or videos.

        enabled: true
        src: "sw.js"
                - match_callback: 'startsWith: /pages/'
                  preload_urls: # List of URLs to preload. The URLs shall match the value in match_callback option
                      - 'page_tos'
                      - 'page_legal'
                      - 'page_articles'
                      - path: 'app_top_articles'
                            display: 5
                      - 'assets/audio/start.mp3'

In addition, you can define URLs generators that will contain the logic for providing several URLs depending on your application needs.

Let say you have 5 different locales and you want to preload all versions of the static pages. With the following service, you will be able to serve all of them at once

src/Generator/StaticPagesUrlGenerator .php

namespace App\Generator;

use SpomkyLabs\PwaBundle\CachingStrategy\PreloadUrlsGeneratorInterface;
use SpomkyLabs\PwaBundle\Dto\Url;
use SpomkyLabs\PwaBundle\Dto\Manifest;
use Symfony\Component\DependencyInjection\Attribute\Autowire;

final readonly class StaticPagesUrlPreloadGenerator implements PreloadUrlsGeneratorInterface
    public function __construct(
        private array $locales,

    public function getAlias(): string
        return 'static_pages';

     * @return iterable<Url|string>
    public function generateUrls(): iterable
        $routeNames = ['page_tos', ...]; //List all route names here
        foreach ($routeNames as $routeName) {
            foreach ($this->locales as $locale) {
                yield Url::create($routeName, ['_locale' => $locale]);

When using the service autoconfiguration, it will automatically be declared. If disable, tag your service with spomky_labs_pwa.preload_urls_generator.


        tags: ['spomky_labs_pwa.preload_urls_generator']

Then, in the bundle configuration you only need to refer to the alias prefixed with a @.

        enabled: true
        src: "sw.js"
                - match_callback: 'startsWith: /pages/'
                      - '@static_pages' #The alias with the "@" prefix

Last updated