Back/forward cache (bfcache): instant back and forward navigation
Published
In one line: Per MDN, the back/forward cache (bfcache) is a performance feature that stores a complete snapshot of a page — including the JavaScript heap — as the user navigates away, so the browser can restore it instantly on a later back or forward navigation instead of repeating the network requests to load it again.
Why it’s faster than the HTTP cache
Section titled “Why it’s faster than the HTTP cache”Per MDN, a regular HTTP cache entry contains only the responses to previous requests; the bfcache instead holds the entire live page in memory, and in-progress code is paused when the user navigates away and resumed when they return. Per web.dev, this makes a bfcache restore faster than even a well-optimized load served from the HTTP cache.
Feature detection and fallback
Section titled “Feature detection and fallback”Here’s pageshow wrapped in an existence check, with event.persisted
distinguishing a bfcache restore from a normal load:
if ('onpageshow' in window) { window.addEventListener('pageshow', (event) => { if (event.persisted) { console.log('This page was restored from the bfcache.'); } else { console.log('This page was loaded normally.'); } });} else { // Fallback for a browser without pageshow support. console.log('This page was loaded normally.');}Per web.dev, pageshow fires right after load on the initial page load, and
again whenever the page is restored from the bfcache; its persisted property
distinguishes the two cases.
Where it is supported
Section titled “Where it is supported”Per web.dev, all major browsers include a bfcache, including Chrome since version 96, along with Firefox and Safari.
What goes wrong
Section titled “What goes wrong”- An
unloadlistener can block bfcache eligibility. Per MDN, some code features — theunloadevent handler is the example MDN names — are not compatible with the bfcache, and their presence on a page can block it from being cached. Per web.dev, this specifically makes a page ineligible in desktop Chrome and Firefox, while Safari may still cache such a page and mobile Chrome and Safari may also attempt to. Per web.dev, the recommended replacement ispagehide, which fires in every caseunloadwould have fired, plus when the page enters the bfcache. - Pending tasks are paused, not cancelled. Per MDN, in-progress JavaScript is paused when the page is stored and resumed on restore — code should not assume a timer or an in-flight promise will keep running while the page is out of view.
- A bfcache restore is not a fresh page load. Because
pageshowcan fire without a precedingload, code that only refreshes stale or sensitive UI state inside aloadlistener will miss a restore; checkevent.persistedand update or re-fetch that state there too. - Monitor blocking reasons instead of guessing. Per MDN, the
PerformanceNavigationTiming.notRestoredReasonsAPI reports why a specific navigation was not served from the bfcache, which is more reliable than inferring the cause from behavior alone.
Where to go next
Section titled “Where to go next”- Core Web Vitals — bfcache restores are counted as separate page visits in Core Web Vitals reporting tools.
- Speculation Rules API — a separate performance reference on this site.