Table of Contents & Menu
Navigation

Back-Forward Cache (bfcache) for Instant Navigation

The back-forward cache (bfcache) is a browser feature that stores full page snapshots in memory, enabling instant navigation when users go back or forward. This dramatically speeds up navigation, boosting Core Web Vitals and user experience.

While Hyvä themes support bfcache, Magento 2's default Cache-Control: no-store header blocks this optimization. Enabling bfcache requires both server-side header modifications and frontend JavaScript adjustments to handle restored page state.

Implementation Overview

Enabling bfcache in a Hyvä theme involves two steps:

  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

By default, Magento 2 sends Cache-Control: no-store, which prevents browsers from caching pages, including bfcache. To enable bfcache, remove the no-store directive from your Varnish VCL configuration, while preserving other cache control behaviors.

Varnish VCL Patch

Apply this patch to your Varnish VCL files (versions 4, 5, and 6). It modifies the Cache-Control header, removing no-store to allow bfcache, while maintaining no-cache, must-revalidate, max-age=0 for standard revalidation:

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 page is restored from bfcache, its JavaScript state is preserved. This can lead to issues where dynamic components (e.g., open menus, analytics, cart totals) need to reset or refresh their data.

Detecting bfcache Restoration

Use the browser's pageshow event to detect when a page is restored from bfcache. The event.persisted property is true when the page came from bfcache:

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

Alpine.js Integration Example

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();
        }
    }
}

Default Theme Compatibility

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

Hyvä Default Theme v1.4+ native components include bfcache-compatible event handlers. However, custom components and third-party scripts (e.g., analytics, chat widgets) require their own pageshow handlers for correct behavior.

Resources