Join the AI Workshop and learn to build real-world apps with AI. A hands-on, practical program to level up your skills.
bfcache (back/forward cache) can cause restored pages to show stale state. For example, with a counter whose state is stored on the server:
When you load the page, the counter shows 0. You increment it to 1, 2, 3 without a full page reload.
Use the back button, then go forward again to the counter page. The counter shows 0 again—not because it was reset, but because the browser restored the page from bfcache.
Refreshing the page loads the current state from the server.
This behavior was observed in Chrome (and Chromium-based browsers like Arc). Safari and Firefox did not show the issue. With Chrome DevTools open and “Disable cache” checked, the issue also did not appear, which can make it easy to miss.
Workaround: Add these meta tags to the document head:
<meta http-equiv="Cache-Control" content="no-cache, no-store" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
The same can be set as HTTP response headers. Example with 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',
},
},
})
Testing can be difficult because bfcache is not easy to clear; using an incognito or private window helps verify the fix.
For more on bfcache, see web.dev/articles/bfcache.
The documentation suggests 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 when a page was restored from bfcache. In Chrome it does not work: event.persisted is always false; this is a known Chrome bug.
This is a known Chrome bug (since 2014).
If you cannot use the no-cache, no-store header, you can force a reload when the page is restored from bfcache. This snippet works around Chrome’s bug:
window.addEventListener(
'pageshow',
function (event) {
if (
event.persisted ||
performance.getEntriesByType('navigation')[0].type === 'back_forward'
) {
location.reload()
}
},
false,
)
This approach is not ideal but can be necessary when meta or response headers are not an option. Bfcache is a lesser-known browser feature worth being aware of when building stateful UIs.