TubeSum ← Transcribe a video

Mastering Full Page Caching in PHP with a Multi-Step Strategy

0h 09m video Published May 23, 2025 Transcribed Aug 3, 2026 T Tideways
Intermediate 5 min read For: PHP developers and web developers interested in caching strategies and performance optimization, particularly those using Symfony or Shopware.
AI Trust Score 70/100
⚠️ Average / Some Fluff

"Delivers a solid technical explanation of ESI caching with real performance numbers, though it's more of a deep dive than a beginner tutorial."

AI Summary

This video explains how Shopware 6.7 implemented a multi-step full page caching strategy using Edge Side Includes (ESI) to improve performance for web applications with many visitors. It compares the traditional full page caching approach with the new ESI-based method, showing how caching different parts of a page separately can save significant processing time.

[00:01]
Introduction to Full Page Caching

Full page caching stores the rendered HTML output to avoid repeated PHP processing and database calls. It can be cached for minutes, hours, or days, and is invalidated when content changes (e.g., stock or price).

[00:32]
Edge Side Includes (ESI) Concept

ESI allows storing different parts of a page as separate cache entries with different lifetimes and dynamic invalidation, so they don't affect each other.

[01:56]
Problem with Traditional Caching

In traditional caching, when a product changes, the entire page is invalidated, causing the header and footer to be re-rendered from scratch, wasting resources.

[02:12]
Shopware 6.7 ESI Implementation

Shopware 6.7 uses ESI to cache header, footer, and main content separately, so an uncached product page can use cached header and footer, saving generation time.

[02:39]
How ESI Works

ESI stores only a reference to cached entries via an ESI include tag, ensuring that even if the main content is cached for a long time, it always uses the newest header and footer.

[03:08]
Symfony and ESI Support

Shopware uses Symfony, which has built-in HTTP cache and ESI support on PHP level, but can also be swapped for Varnish reverse proxy.

[03:22]
Code Implementation in Shopware

The ESI tag is rendered in the storefront base HTML Twig template using the render_esi function, mapping to a header controller that loads data via a header loader.

[04:19]
Comparison with Shopware 6.6

In 6.6, the header was rendered directly in the page, taking 50-100ms or more. The generic page loader called header and footer loaders on every request.

[05:29]
Benefits of ESI in Shopware

With ESI, the header and footer generation is offloaded to a separate controller that can be cached, eliminating the need to run that code on every request.

[06:10]
Performance Impact

Using Tideways profiler, the header and navigation loading took 40ms, and rendering took 65ms, totaling 110ms. With caching, this is only done once, saving 110ms per page.

[07:39]
Measured Improvement

Comparing 100 product page traces, there's a performance drop of around 250ms between 6.6 and 6.7, with a good chunk attributed to the ESI header change. The generic page loader is 30% slower in old code, and removing it reduces time by 48ms.

Edge Side Includes provide a clever way to cache different parts of a page independently, leading to significant performance gains. Shopware 6.7's implementation shows a measurable improvement of around 250ms per page, making it a valuable strategy for high-traffic web applications.

Mentioned in this Video

Tutorial Checklist

1 03:22 In the storefront base HTML Twig template, use the render_esi function to render an ESI tag for the header.
2 03:48 Map the ESI tag to a controller (e.g., header controller) that loads data via a header loader and renders the header template.
3 05:29 Offload header and footer generation to separate controllers that can be cached using ESI.
4 06:10 Use a profiler like Tideways to measure the performance impact and compare before/after traces.

Study Flashcards (5)

What is the main benefit of using Edge Side Includes (ESI) in full page caching?

easy Click to reveal answer

ESI allows different parts of a page to be cached separately with different lifetimes, so they can be invalidated independently without affecting each other.

00:32

In traditional full page caching, what happens when a product's stock or price changes?

easy Click to reveal answer

The cache is invalidated, and the next visitor gets an uncached page, which re-renders the main content, header, and footer from scratch.

01:56

How does ESI avoid the problem of stacking different cache lifetimes?

medium Click to reveal answer

ESI stores only a reference to the cached entries with an ESI include tag, so even when the main content is cached for a long time, it always uses the newest header and footer from the cache.

02:39

What is the performance improvement measured in Shopware 6.7 compared to 6.6?

medium Click to reveal answer

Around 250 milliseconds per page, with a good chunk attributed to the ESI header change.

07:39

What is the role of the render_esi function in Symfony?

medium Click to reveal answer

It renders an ESI include tag that references a cached fragment, allowing separate caching of page parts.

03:35

💡 Key Takeaways

💡

ESI allows independent caching of page parts

This is the core concept that enables significant performance gains by caching header and footer separately.

00:32
🔧

ESI stores references, not content

This clever mechanism ensures that cached pages always use the latest header and footer without full invalidation.

02:39
📊

Measured 110ms savings per page

Concrete numbers show the tangible benefit of ESI caching in a real-world application.

06:10
📊

Overall 250ms improvement in 6.7

Demonstrates the cumulative impact of ESI on overall page performance.

07:39

[00:01] performance optimization for web applications with many visitors. Instead of performing all the PHP processing and database work to render the same page over and over again, you can cache the resulting HTML once and serve that for a

[00:17] period of time. And if you want to get even more out of full page caching, edge site includes is a standard that has a clever approach to this topic. It allows storing different parts of a page as their own cache entries in such a way

[00:32] that they can even have different cache lifetimes and dynamic invalidation without affecting each other. Mo I am Benjamin and in this video I will look at how Shopware 6.7 implemented a multi-step full page cache in practice

[00:48] that yields a significant performance improvement. But let's walk back and quickly review traditional full page caching using Shopware as an example. In the simplest case, caching the HTML output of a web application can be based

[01:03] output of a web application can be based on the URL and HTTP request method. This assumes that there are no differences in the HTML response output across different users. For example, when there are users different based on the browser

[01:17] language, when they are locked in or have guest status, or when different cookies or the session affects the output as soon as the page is generated

[01:29] by the application, it could be cached for as short as a few minutes, uh, hours or even days so that all consecutive users visiting the same URL get the

[01:41] response page from the full page. cache circumventing repeated database calls or calls to external services. This saves a lot of performance. In the case of Shopware, when stock or price of the product

[01:56] changes, the cache gets invalidated and the next visitor gets the uncashed page again. This rerenders the main content but also header navigation completely from scratch. Shopware 6.7 now uses edge sites

[02:12] includes to achieve different cache entries and lifetimes for the header and footer and the main content. An uncached product page can then use a cached header and footer and save the time generating and rendering them. For a

[02:27] naive page cache implementation, this can cause a problem of stacking different cache lifetimes and during invalidation. Edge set includes cleverly work around this problem by storing only a reference

[02:39] to the cached entries with the ESI include tag. That means even when the product page output is cached for a long time, it is always rendered with the newest header and footer output from the cache. Let's look at how Shopware

[02:55] implements this in code and how it changed between versions 6.6 6 and 6.7 to better understand edge site includes and how they improve performance. Shopware uses the Symfony framework under the hood and Symfony comes with a

[03:08] under the hood and Symfony comes with a fullyfledged HTTP cache and ESI support on the PHP level but it can also be swapped for a more complete solution based on the varnish reverse proxy. The entry point to this code and Shopware is

[03:22] in the storefront base HTML Twick template. If we scroll down, we see the Symfony code to render an ESI tag for the front end header. Here there's a

[03:35] function called render ESI. This renders the ESI include tag that you've seen the ESI include tag that you've seen before. Here in this case, the ESI tech before. Here in this case, the ESI tech is for the front end header uh route.

[03:48] And if we look in the navigation controller of Shopware, this maps to the controller called header. And the header is loading all data from this header loader object and renders the header

[04:02] loader object and renders the header template. differs from how it worked before. In Shopware 6.6 uh we already see the code with the feature flag for the ESI support but we

[04:19] also see what the old code did. So in case of Shopware 6.6 six and all versions before instead of rendering the ESI tag it's actually rendering the header output here including the navigation and in case of Shopware the

[04:35] navigation can take a few milliseconds uh 50 milliseconds 100 milliseconds and even up to a few hundred milliseconds in some cases in Shopware 6.6 six. The data

[04:47] for this content is loaded by a class called generic page loader. The generic called generic page loader. The generic page loader uh if you look at it, you page loader uh if you look at it, you see it runs some code if the feature

[05:01] flag cache rework is not activated. You see it calls the header loader load function. It calls the respective footer loader loading all the data it needs for

[05:14] loader loading all the data it needs for a navigation and footer of the page uh in every request. Going back to the navigation controller, we can see in case of the ESI rendering um the header loader is

[05:29] offloaded to this new controller here. So what this change uh allows Shopware So what this change uh allows Shopware to do is to get rid of all this code here and um you don't even need to run this anymore. All the database and

[05:43] processing work to generate the header and the footer is offloaded to the new and the footer is offloaded to the new controller that can be cached using ESI. Let's switch to the current branch uh for 6.7 and we see the same code for the

[05:58] generic page loader here and see how it fits on one page. Um all the code that was um used before to generate the navigation is now not needed anymore.

[06:10] obviously most interested in the performance impact of this change. We can look at this in tight ways profiler can look at this in tight ways profiler and see an aggregated trace of 100

[06:23] different product pages where we can see the header page loader and the navigation page loader. Um, as you might remember, they were previously loaded in

[06:36] the generic page loader of every page of Shopware 6.6 six. this data takes 40 milliseconds. And then we can also see

[06:52] that rendering this data in the twig template again takes template again takes um about another 65 second milliseconds. So in total we have 110 milliseconds of rendering the navigation. And by

[07:09] introducing caching for the header, uh, we can make sure that this is only rendered once. And we save 110 milliseconds for every new additional milliseconds for every new additional product page, every category page until

[07:24] the cache for the navigation runs out and it needs to be regenerated and it needs to be regenerated once. We can compare this to a trace afterwards um by using the compare feature in tightways again comparing

[07:39] against 100 uh traces um of product pages. And we can see here that there's pages. And we can see here that there's a performance drop of around 250 milliseconds between version 6.6 and 6.7. Not all of this can be attributed

[07:55] to this ESI header change, but a good uh chunk of it um is related to this new feature. When we switch the compare order between both traces, we can see order between both traces, we can see how much the improvement is. So here in

[08:10] how much the improvement is. So here in the old request, we see that the generic page loader is 30% uh slower in the old code because of this change. And um removing this code um reduces the the time by yeah 48

[08:26] milliseconds. And the same is true for the base navigation. We saw that before the base navigation. We saw that before around 65 milliseconds of rendering here around 65 milliseconds of rendering here makes the um Shopware 6.6 rendering much

[08:39] slower. This was a quick rundown of how edge site includes work in Shopware and Symfony to affect meaningful performance improvements. If you're interested in more content, a few more suggestions will pop up on your screen. If you would

[08:54] like to be informed about new content, please subscribe to our newsletter on tideway.com. The link is in the description.

More from Tideways

View all

⚡ Saved you 0h 09m reading this? Transcribe any YouTube video for free — no signup needed.