# Back/forward cache (bfcache): instant back and forward navigation

> How the back/forward cache stores a full in-memory snapshot of a page — including the JavaScript heap — so back and forward navigations can restore it instantly, why an unload listener can block eligibility in some browsers, and how to detect a bfcache restore with the pageshow event's persisted property.

**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

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

Here's `pageshow` wrapped in an existence check, with `event.persisted`
distinguishing a bfcache restore from a normal load:

```js
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

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

## What goes wrong

- **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.

## Where to go next

- [Core Web Vitals](/reference/performance/core-web-vitals/) — bfcache restores are
  counted as separate page visits in Core Web Vitals reporting tools.
- [Speculation Rules API](/reference/performance/speculation-rules/) — a
  separate performance reference on this site.