Skip to content

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.

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.

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.

Per web.dev, all major browsers include a bfcache, including Chrome since version 96, along with Firefox and Safari.

  • An unload listener can block bfcache eligibility. Per MDN, some code features — the unload event 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 is pagehide, which fires in every case unload would 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 pageshow can fire without a preceding load, code that only refreshes stale or sensitive UI state inside a load listener will miss a restore; check event.persisted and update or re-fetch that state there too.
  • Monitor blocking reasons instead of guessing. Per MDN, the PerformanceNavigationTiming.notRestoredReasons API reports why a specific navigation was not served from the bfcache, which is more reliable than inferring the cause from behavior alone.
  • 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.