Performance

Non-Cacheable Blocks That Break Full-Page Cache

One block marked cacheable="false" makes the whole page skip full-page cache. Here is how to find these blocks and serve dynamic content the right way.

Jason Schuman · May 13, 2026

One block can make an entire page uncacheable

Magento's full-page cache is powerful and easy to defeat by accident. A single block marked as non-cacheable makes the whole page skip the cache, not just that block.

We find this in most performance audits. A theme or extension marked one block cacheable="false", and a high-traffic page has been bypassing the cache ever since, at full origin cost per request.

This article covers how Magento decides a page is not cacheable, where these blocks come from, how to find them, and the right way to put dynamic content on a cached page.

How Magento decides a page is not cacheable

Cacheability is set per block in layout XML, through the cacheable attribute. By default blocks are cacheable, and the full-page cache stores the rendered response.

The rule that catches people is the aggregation. If any block anywhere on the page is marked cacheable="false", Magento treats the entire page response as non-cacheable.

So the blast radius of one careless attribute is the whole page, and if that block sits in a shared layout handle, the blast radius is every page that uses it.

Where these blocks come from

Almost always, a non-cacheable block is a shortcut. A developer needed a piece of content to always be fresh, marked the block cacheable="false", and moved on.

Sometimes it is an extension doing the same thing inside its own layout XML, which means you inherit the problem by installing it. Either way the content could usually have stayed fresh without disabling the cache for the entire page.

A single cacheable="false" block in a shared layout handle can make every page that uses it bypass the full-page cache. It is one of the highest-impact findings in a performance audit.

Finding them in layout XML

These are searchable, which makes them fast to inventory. Grep the theme and module layout files for the attribute:

grep -rn 'cacheable="false"' app/design app/code vendor/*/*/view

Every hit is a candidate. Note which layout handle each one lives in, because a block in default.xml or another global handle affects far more pages than one scoped to a single page type.

Core Magento uses this attribute intentionally in a few places, so not every hit is a defect. The ones to focus on are the additions from your theme and your installed extensions.

Confirming the impact

Layout XML tells you a block opts out. To confirm a real page is not being cached, check the response directly.

In developer mode, Magento adds an X-Magento-Cache-Debug header to responses, reporting a HIT or MISS for the full-page cache. A page that always returns MISS, despite the cache being enabled, is a page something is marking non-cacheable.

Behind Varnish, the same question is answered by inspecting the response headers or the Varnish log. A page that never caches is where your origin is quietly paying full price on every visit.

The cost of a page that never caches

It helps to be concrete about what a non-cacheable page costs. A cached page is served from Varnish in a few milliseconds, with no PHP and no database work at all.

The same page marked non-cacheable runs the full Magento stack on every request: PHP, database queries, and layout rendering, the whole path. On a high-traffic page that is the difference between trivial load and an origin working hard for results it could have cached.

Multiply it across every affected page and every visit, and one layout attribute becomes a measurable share of total server load. That is why these findings rank so high despite having a one-line cause.

The right way to do dynamic content on a cached page

Disabling the cache is almost never the correct way to show dynamic content. Magento has purpose-built mechanisms for exactly this.

Per-customer content belongs in private content sections, loaded through the customer-data JavaScript and declared in sections.xml. The cart summary and customer greeting work this way: the page stays cached, and the personal parts load separately on the client.

For server-rendered fragments that vary, Varnish supports ESI, which caches the page and the fragment on different schedules. Both approaches keep the full-page cache working while still showing fresh content, which is what cacheable="false" gave up entirely.

A high-value fix

Non-cacheable blocks are among the cheapest performance wins to find and the most expensive to leave in place. One grep and one header check locate them, and converting them to private content sections restores caching on the affected pages.

Fixing them is usually a small code change with an outsized effect on origin load, which is a rare ratio in performance work. Most wins cost more than one line.

Knowing which blocks are silently disabling your full-page cache, and on how many pages, turns an invisible origin-load problem into a short, concrete fix list. That is exactly the kind of finding a performance review is built to surface.