SharePointVault ~/gotchas/spfx ⌕ Search 404 pages, error messages, scripts…Ctrl K ★ Star
M↓ README.mdM↓ list-pages-run-stale-extension-bundles-from-cache-storage.md
sharepoint-vault›gotchas›spfx›list-pages-run-stale-extension-bundles-from-cache-storage.mdhistoryedit on GitHub
● GOTCHAspfx· 3 min read

List and library pages run a stale extension bundle from Cache Storage for days

applies to: SharePoint Online (modern list and library pages)reviewed: 2026-09-24#spfx#extensions#application-customizer#command-set#cdn#caching

If an SPFx extension loads a bundle whose URL never changes (no content hash – the usual trick to update a tenant-wide extension without a new .sppkg), modern list and library pages can keep executing an old copy for days. The Lists web app stores extension scripts in its own Cache Storage (Lists-odsp-web-prod_<build>) and runs them from there, whatever your Cache-Control header says. Site pages pick up the new file within minutes; list pages don't.

Když SPFx rozšíření načítá bundle se stálou adresou (bez content-hashe – obvyklý trik, jak aktualizovat rozšíření bez nového .sppkg), stránky seznamů a knihoven mohou ještě dny spouštět starou kopii. Aplikace Seznamy si skripty rozšíření ukládá do vlastní Cache Storage (Lists-odsp-web-prod_<build>) a spouští je odtud bez ohledu na hlavičku Cache-Control. Běžné stránky webu novou verzi vezmou během minut, seznamy ne.

Symptom

You publish a new version of the bundle behind a stable URL (for example my-extension.js on your CDN, Cache-Control: max-age=600). On a modern site page the new code runs right away. On a document library or list view in the same browser, the old code keeps running:

  • a hard refresh (Ctrl+Shift+R) shows the new version,
  • the next normal refresh shows the old one again,
  • the script loads in a few milliseconds, as if from a local cache, so it looks like a caching glitch that should have expired long ago.

In our case the cached copy was the file as published nine days earlier (its Last-Modified), stored with max-age=600.

Cause

The modern Lists experience keeps its own cache of scripts in the browser's Cache Storage API, one cache per Lists build (Lists-odsp-web-prod_2026-09-04.002, Lists-odsp-web-prod_2026-09-11.002, …). Your extension bundle ends up in it and is executed from it. There is no service worker involved (navigator.serviceWorker.controller is null) – the page code reads the cache itself, so HTTP caching rules don't apply. An entry in an older build's cache keeps winning even when a newer build's cache exists.

Modern site pages have similar caches (SPClient-<id>), but there the new file showed up within minutes.

How to confirm

Run in the console of a list or library page:

for (const name of await caches.keys()) {
  const c = await caches.open(name);
  for (const req of await c.keys()) {
    if (req.url.includes('my-extension')) {
      const res = await c.match(req);
      console.log(name, req.url, res.headers.get('last-modified'));
    }
  }
}

An entry with an old last-modified is the copy that runs. Deleting it (await c.delete(req)) and doing a normal refresh runs the current file, and the Lists app stores the new copy.

Fix

  • Don't put logic behind a stable URL. Keep the stable file a tiny loader that rarely changes, and have it load the real code from a versioned URL (a version folder or a content hash). A new URL can't be served from an old cache entry.
  • Keep the stable part backwards compatible with both older and newer versions of whatever it loads – for days, both combinations will be running at the same time.
  • Verify releases on a list page too, and read Cache Storage first. Otherwise you measure the old copy and chase a bug that isn't in the code.
  • Don't promise users that an extension update shows up "within minutes" everywhere.

Related

Was this helpful?ask or add your experience on GitHub →
Saved you an hour? A star on GitHub helps other SharePoint people find the vault.★ Star on GitHub
last reviewed: 2026-09-24last updated: 2026-09-24historyedit on GitHubview source