Two separate levers, used correctly
HTML minification and block cache get treated as a single lever far too often in practice, but they're technically completely independent. Here's where minification hits its limits, how to tune TTL beyond the basics, and how overly granular cache keys make the cache useless in practice.
Table of Contents
- 1. Two separate levers, often confused
- 2. Magento's HTML minification setting in detail
- 3. The limits of minification: what must not be touched
- 4. Block cache lifetime beyond the basics
- 5. getCacheKeyInfo() and the risk of overly granular cache keys
- 6. Detecting cache fragmentation: hit rate and Redis keyspace
- 7. Practical example: refactoring an overly granular cache key
- 8. How full page cache and block cache interact in Hyvä
- 9. Monitoring and a fine-tuning checklist
- 10. Summary
- 11. FAQ
1. Two separate levers, often confused
HTML minification strips whitespace, line breaks, and comments from the delivered markup to reduce the transferred file size. Block cache, on the other hand, stores the result of a rendered block across multiple requests to avoid repeated PHP rendering. Both mechanisms visibly reduce response time in the end, but they operate at completely different points in the rendering pipeline.
In practice both levers get confused regularly, for instance when a team expects a noticeable performance gain right after enabling minification, one that would actually only come from additional cache tuning. Keeping the two mechanisms cleanly separated makes it possible to decide more precisely which measure actually fits which concrete problem.
2. Magento's HTML minification setting in detail
The dev/template/minify_html setting sits under Stores, Configuration, Advanced, Developer, Template Settings in the admin panel and strips unnecessary whitespace and HTML comments from the final markup during rendering. It operates at the level of the whole page, after all blocks have been merged, not at the level of individual templates.
The effect on actual file size is often smaller than expected in practice, especially when gzip or brotli compression is already active at the web server level. Compression already removes redundant whitespace patterns very efficiently, which means the additional effect of HTML minification comes out noticeably smaller on already compressed responses than the uncompressed size difference would suggest.
bin/magento config:set dev/template/minify_html 1
bin/magento cache:flush
3. The limits of minification: what must not be touched
Inline script blocks registered through registerInlineScript for the content security policy must not have their content or byte order changed by minification, since the associated CSP hash would no longer match and the browser would block the script. Magento's minification logic accounts for that by default, but for highly custom inline script constructs it's worth checking the browser console for CSP violations after every change.
Embedded JSON-LD for structured data is just as critical. Whitespace inside a JSON-LD block is syntactically harmless, but a faulty minification rule that accidentally changes quotes or commas inside string values can invalidate the entire structured data object. A test with Google's Rich Results Test should follow every minification change to rule out silent JSON-LD damage.
4. Block cache lifetime beyond the basics
Beyond the basic setting where a block is either cacheable or not, the actual lifetime of a cache entry can be controlled per block type through getCacheLifetime(). A static marketing banner can safely get a lifetime of several hours, while a block showing frequently changing stock levels needs a noticeably shorter one, without the two blocks needing entirely different treatment otherwise.
The value returned by getCacheLifetime() is in seconds and works together with the regular cache invalidation mechanism based on cache tags. That means a block can get invalidated either by a fixed TTL or by an event such as a product update, whichever of the two signals happens first.
public function getCacheLifetime(): int
{
// Stock widget: short TTL so stale stock displays
// don't linger for too long.
return 300;
}
5. getCacheKeyInfo() and the risk of overly granular cache keys
A block's cache key determines how many different variants of the same block can exist in the cache at once. Packing too many dynamic values into getCacheKeyInfo(), say store, customer group, currency, and an individual page parameter on top, theoretically creates a separate cache entry for every combination of those values, most of which never get requested a second time in practice.
The result is a low cache hit rate despite an active block cache, because nearly every request technically counts as a new, unique combination and has to be freshly rendered. The cache keeps filling up with entries that never get read a second time, consuming memory and compute time for cache writes without delivering the expected performance benefit.
public function getCacheKeyInfo(): array
{
return [
'PRODUCT_LIST_WIDGET',
$this->_storeManager->getStore()->getId(),
$this->_design->getDesignTheme()->getId(),
$this->httpContext->getValue(CustomerGroup::CONTEXT_GROUP),
// Deliberately NOT: $this->getRequest()->getParam('p', 1)
// A page parameter would create a separate cache entry
// per page and destroy the hit rate.
];
}
6. Detecting cache fragmentation: hit rate and Redis keyspace
A first indicator of fragmentation is a low cache hit rate relative to the number of cache writes, measurable through Redis statistics or a corresponding monitoring dashboard. If the number of keys in the Redis keyspace keeps growing without a matching improvement in hit rate, that strongly points to overly granular cache keys.
A direct look into the Redis keyspace with a pattern filter on the affected block type often reveals the scale of the problem immediately: instead of the few dozen expected variants, several thousand keys show up for the same block, differing only in a single, too-granular part of the cache key.
redis-cli --scan --pattern "*PRODUCT_LIST_WIDGET*" | wc -l
redis-cli info stats | grep -E "keyspace_hits|keyspace_misses"
7. Practical example: refactoring an overly granular cache key
In one real case, a product list widget's cache key included the full query string of the current page, sort and filter parameters included, on top of store and customer group. The result was a hit rate below ten percent for that block type, even though the underlying product assortment only changed a few times per day.
The fix was removing the query string from the cache key and instead deliberately including the actually varying parameters, sorting and active filters, individually in the key rather than pulling in the whole query string wholesale. The hit rate afterward rose above eighty percent, with the correctness of the delivered content unchanged.
8. How full page cache and block cache interact in Hyvä
In a Hyvä theme, the full page cache handles delivering the complete, largely static page, while private, customer-specific content such as cart quantities or the customer name gets loaded client-side through private content via Alpine.js, independently of the cached base markup. Block cache tuning in this model only concerns areas that are neither fully static nor fully private, such as product lists with customer-group-dependent pricing.
If such a block accidentally ends up with an overly granular cache key, that doesn't affect the full page cache itself, only the rendering time within an otherwise already cached page. The effect is therefore more subtle and often gets noticed in practice only through increased server load, not through obviously slow page loads in the browser.
9. Monitoring and a fine-tuning checklist
A sensible fine-tuning workflow starts with regularly checking the Redis keyspace statistics for the highest-traffic block types, followed by a targeted review of the getCacheKeyInfo() implementation for any block with a noticeably low hit rate. Only after that does adjusting TTL values pay off, since a shorter TTL can't compensate for a badly configured cache key granularity, it only masks the problem.
The table below ranks the levers covered here by their impact and shows that HTML minification, while easy to enable, contributes a noticeably smaller share of the actual response time compared to clean cache key design.
| Lever | Level of effect | Typical outcome | Risk if misused |
|---|---|---|---|
| dev/template/minify_html | Delivered HTML | Small file size reduction | Breaks CSP hash for inline scripts |
| getCacheLifetime() per block | Block cache TTL | Fresher data with a short TTL | Too short a TTL barely relieves the cache |
| getCacheKeyInfo() granularity | Number of cache variants | High hit rate with clean design | Cache fragmentation with too many fields |
| Redis keyspace monitoring | Diagnosis, no direct effect | Early detection of fragmentation | The problem stays invisible without monitoring |
| Full page cache plus private content | The entire page | Biggest overall performance lever | Misclassified private content inside the FPC |
Mironsoft
Hyvä theme development and Luma migration
Still running Luma, or a Hyvä theme that just doesn't feel right?
We build Hyvä themes for Magento from scratch or migrate existing Luma shops cleanly, with Tailwind CSS, Alpine.js, and none of the unnecessary JavaScript baggage.
Luma-to-Hyvä Migration
Move an existing shop to Hyvä in a structured way, without losing functionality.
Custom Theme Development
Build a custom Hyvä theme from scratch based on your design.
Performance Optimization
Improve Core Web Vitals and load times in the Hyvä frontend with purpose.
10. Summary
HTML Minification and Caching Fine-Tuning: Key Facts at a Glance
Separate levels
HTML minification and block cache solve different problems and should be evaluated independently.
Minification limits
Inline scripts with a CSP hash and JSON-LD blocks need a test after every minification change.
Cache key design
Only genuinely varying values belong in getCacheKeyInfo(), otherwise the hit rate drops sharply.
Monitoring
Redis keyspace statistics reveal fragmentation earlier than a subjectively perceived load time.