Skip to content

Had an issue with bfcache

Today I learned about bfcache when someone pointed out a problem on an example I did of a counter in htmx.

You load the page, counter (whose state is stored on the server) is at 0.

Increment counter, 1, 2, 3. Increment happens without a full page reload.

Go back to a previous page in your browser with the back button, then go forward again to the counter.

Counter is at 0 again.

Not because it reset, but because the browser cached the first full page load in its bfcache (back/forward cache).

You need to refresh the page to see the actual count value.

This only happened in Chrome (and Chrome-based browsers like Arc). Safari? No problem. Firefox? No problem. And also, Chrome with DevTools open with “Cache disabled” setting? No problem (that’s why I didn’t notice).

Solution?

I added these meta tags to my HTML head tag:

<meta http-equiv="Cache-Control" content="no-cache, no-store" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />

I could also set them as HTTP headers, for example using Astro:

import { defineConfig } from 'astro/config'
import node from '@astrojs/node'

export default defineConfig({
  output: 'server',
  adapter: node({
    mode: 'standalone',
  }),
  server: {
    headers: {
      'Cache-Control': 'no-cache, no-store',
      Pragma: 'no-cache',
      Expires: '0',
    },
  },
})

I had a hard time testing this because I couldn’t find a good way to clear the bfcache, until I had the idea of testing in incognito mode, and I was able to see it worked fine.

Read more about bfcache: https://web.dev/articles/bfcache

Note that they suggest using

window.addEventListener('pageshow', (event) => {
  if (event.persisted) {
    console.log('This page was restored from the bfcache.')
  } else {
    console.log('This page was loaded normally.')
  }
})

to detect a page was restored but this didn’t work at all, persisted is always false and this might be a bug.

Actually it is a bug in Chrome since 2014 🥲

If the no-cache no-store header is not an option, one snippet I found on StackOverflow to reload the page if page was detected to be from the bfcache, taking into consideration Chrome’s “bug”:

window.addEventListener(
  'pageshow',
  function (event) {
    if (
      event.persisted ||
      performance.getEntriesByType('navigation')[0].type === 'back_forward'
    ) {
      location.reload()
    }
  },
  false,
)

…not optimal, of course.

But interesting.

Never heard of bfcache before.

→ Get my HTML Handbook

I wrote 17 books to help you become a better developer, download them all at $0 cost by joining my newsletter

JOIN MY CODING BOOTCAMP, an amazing cohort course that will be a huge step up in your coding career - covering React, Next.js - next edition February 2025

Bootcamp 2025

Join the waiting list