Skip to content

Back-Forward Cache (bfcache) for Instant Navigation

The back-forward cache (bfcache) is a browser optimization for instant page restoration. When users click the browser's back or forward buttons, bfcache restores complete page snapshots from memory instead of reloading the entire page. This browser caching mechanism dramatically improves navigation performance and Core Web Vitals metrics by providing nearly instantaneous page transitions.

Hyvä themes are bfcache-compatible, but Magento 2's default Cache-Control: no-store header blocks browser page caching. Enabling bfcache for instant back-forward navigation requires two changes: modifying server cache control headers to allow browser page storage, and adding frontend JavaScript handlers to reset component state when pages are restored from the browser cache.

Implementation Overview

Enabling bfcache in a Hyvä theme involves two components:

  1. Backend Configuration: Modify Varnish or Fastly VCL to remove no-store from the Cache-Control header, allowing browsers to cache pages for back-forward navigation
  2. Frontend Implementation: Add pageshow event listeners to JavaScript components that need to reset state or refresh data when a page is restored from cache

Backend Configuration: Removing no-store from Cache Headers

Magento 2 sends Cache-Control: no-store by default, which explicitly prevents browsers from storing pages in any cache, including the bfcache. To enable browser back-forward caching, modify the Varnish VCL configuration to remove the no-store directive while preserving other cache control behaviors that prevent regular HTTP caching.

Varnish VCL Patch for bfcache Support

The following VCL patch enables bfcache by changing the server-sent Cache-Control header. The modification removes no-store from the header value while keeping no-cache and must-revalidate, which allows browsers to store pages in the bfcache for instant back-forward navigation while still preventing traditional HTTP caching of dynamic Magento content.

Apply this patch to your Varnish VCL files for versions 4, 5, and 6. Each version requires the same single-line change in the vcl_deliver subroutine:

Varnish VCL Patch for bfcache Support

This patch was generated using the default Magento vcl.

diff --git a/etc/varnish4.vcl b/etc/varnish4.vcl
index ffb489c..07e0fd6 100644
--- a/etc/varnish4.vcl
+++ b/etc/varnish4.vcl
@@ -212,7 +212,7 @@ sub vcl_deliver {
    if (resp.http.Cache-Control !~ "private" && req.url !~ "^/(pub/)?(media|static)/") {
        set resp.http.Pragma = "no-cache";
        set resp.http.Expires = "-1";
-        set resp.http.Cache-Control = "no-store, no-cache, must-revalidate, max-age=0";
+        set resp.http.Cache-Control = "no-cache, must-revalidate, max-age=0";
    }   
    if (!resp.http.X-Magento-Debug) {
diff --git a/etc/varnish5.vcl b/etc/varnish5.vcl
index 3347b93..6f72ad0 100644
--- a/etc/varnish5.vcl
+++ b/etc/varnish5.vcl
@@ -209,7 +209,7 @@ sub vcl_deliver {
    if (resp.http.Cache-Control !~ "private" && req.url !~ "^/(pub/)?(media|static)/") {
        set resp.http.Pragma = "no-cache";
        set resp.http.Expires = "-1";
-        set resp.http.Cache-Control = "no-store, no-cache, must-revalidate, max-age=0";
+        set resp.http.Cache-Control = "no-cache, must-revalidate, max-age=0";
    }   
    if (!resp.http.X-Magento-Debug) {
diff --git a/etc/varnish6.vcl b/etc/varnish6.vcl
index 4e07ac5..e32be55 100644
--- a/etc/varnish6.vcl
+++ b/etc/varnish6.vcl
@@ -215,7 +215,7 @@ sub vcl_deliver {
    if (resp.http.Cache-Control !~ "private" && req.url !~ "^/(pub/)?(media|static)/") {
        set resp.http.Pragma = "no-cache";
        set resp.http.Expires = "-1";
-        set resp.http.Cache-Control = "no-store, no-cache, must-revalidate, max-age=0";
+        set resp.http.Cache-Control = "no-cache, must-revalidate, max-age=0";
    }   
    if (!resp.http.X-Magento-Debug) {

Alternative: Third-Party Extensions

For more granular control over caching headers without manual VCL modifications, consider the Elgentos VarnishExtended extension.

Fastly Configuration

Fastly CDN requires similar VCL modifications. For Fastly-specific instructions, see the Mage-OS Theme Optimization module documentation.

Frontend Implementation: Handling Restored Page State

When a browser restores a page from bfcache, the page's JavaScript state is preserved exactly as it was when the user navigated away. Dynamic components like open mobile menus, modal dialogs, or loading spinners remain in their previous state after bfcache restoration. Analytics trackers, cart totals, and other data-dependent components may display stale information because they don't re-execute their initialization code during bfcache page restoration.

To handle bfcache page restoration properly, frontend components must detect when the page is restored from the browser cache and reset their state or refresh their data as needed.

Detecting bfcache Page Restoration with pageshow Event

The browser's pageshow event fires whenever a page becomes visible, including both normal page loads and bfcache restorations. The event.persisted property indicates whether the page was restored from bfcache (true) or freshly loaded (false).

Use this event listener pattern to detect bfcache restoration and trigger component state resets:

window.addEventListener('pageshow', (event) => {
    if (event.persisted) {
        // Page was restored from bfcache - reset state as needed
        console.log('Page restored from browser back-forward cache');
    }
});

The event.persisted property is the reliable indicator for bfcache restoration. Always check this property rather than assuming every pageshow event represents a restoration.

Resetting Component State with Alpine.js

Alpine.js components in Hyvä themes can listen for the pageshow event using Alpine's event binding syntax. The following example demonstrates how to reset mobile menu state when a page is restored from bfcache.

Resetting Mobile Menu on bfcache Restore

In your mobile.phtml template, add the x-bind directive to the component's root element:

x-bind="eventListeners"

Add the eventListeners object to the Alpine component's data to close the menu when the page is restored:

eventListeners: {
    ['@pageshow.window'](event) {
        if (event.persisted) {
            this.closeMenu();
        }
    }
}

bfcache Compatibility in Hyvä Default Theme

Built-in bfcache Support in Hyvä Default Theme v1.4+

All native components in Hyvä Default Theme version 1.4 and later include bfcache-compatible pageshow event handlers. Custom components and third-party scripts (analytics, chat widgets, etc.) must implement their own pageshow handlers to ensure correct behavior when pages are restored from the browser back-forward cache.

Resources