Smart invalidation deep-dive
Smart invalidation is the default mode. Instead of purging “everything related to product X” when a product changes, it inspects which fields actually changed and computes the minimum set of cache tags that must die.
This page explains the field-to-tag mapping so you can predict what a given save will invalidate — and decide whether Smart is right for your store.
Why field-level matters
Section titled “Why field-level matters”Stock Shopware invalidation operates at the entity level: any change to product X invalidates everything tagged with product-X. That tag is typically attached to:
- The product detail page
- Every category page the product appears on
- Every listing query that returned the product
- The async buybox component
- The home page if the product is featured
So a one-character fix in the description re-renders dozens of pages — many of which don’t even display the description.
Smart mode breaks the entity tag into a per-field tag set. Listings carry product-X.name + product-X.price + product-X.coverImage; detail pages carry the full set; buybox carries product-X.price + product-X.deliveryTime + product-X.stock. A description-only change matches only the detail page’s tag set, so only that one entry is purged.
Examples
Section titled “Examples”| Changed field on a product | Smart invalidates |
|---|---|
name | Detail + listings (name shown in cards) + category pages (referenced in breadcrumb associations) |
description | Detail only |
price | Detail + listings + buybox + home (if featured) |
stock | Detail + buybox |
deliveryTime | Buybox only |
coverId (cover image) | Detail + listings |
metaTitle / metaDescription / keywords | Detail only |
categoryIds (assignment change) | Detail + every old & new category page + listings |
active | Detail + listings + category pages |
properties (assignment) | Detail + filter aggregations |
visibilities (sales-channel assignment) | Detail + listings + category pages in affected channels |
| Changed field on a category | Smart invalidates |
|---|---|
name | Category page + parent listings + navigation menus |
description | Category page only |
parentId (move) | Old & new category trees + navigation menus |
active | Whole tree under it |
productAssignmentType / productStreamId | Category page + listings |
| Changed field on a CMS page | Smart invalidates |
|---|---|
name / sections / slots | The CMS page entry |
| Assignment to a category | The category page + the CMS page |
Custom fields
Section titled “Custom fields”Custom fields are bucketed conservatively — they invalidate the detail page plus listings if the custom field appears in a property block typically shown on cards.
If you have a custom field that controls only the detail page output (e.g. a “warranty” rich-text block), Smart still treats it as listing-affecting by default, to be safe. Override the mapping if you know better — see the Extending Smart section below.
When Smart over-purges (and when it doesn’t)
Section titled “When Smart over-purges (and when it doesn’t)”Smart is conservative. When in doubt, it purges more rather than risk leaving a stale page. Cases where it deliberately over-purges:
- Bulk product import via DAL — Shopware fires write events with a single “everything was set” payload. Smart can’t tell which fields effectively changed and purges everything.
- First save after a migration — same reason as above.
- A non-tracked field whose value matters — e.g. you added a Twig macro to your theme that reads a non-tracked custom field. Smart doesn’t know your theme reads it, so it won’t purge listings when that field changes.
For the first two, expect a one-off large purge after big imports. For the third, switch to Precise or Extended for that one save, or add a manual purge from your import script.
Cases where Smart is the wrong default
Section titled “Cases where Smart is the wrong default”- You run a content site, not a shop — content rarely changes; the over-purges from Precise / Extended aren’t worth the analysis overhead.
- You always do bulk changes — Smart and Precise will both purge most of the cache on bulk imports anyway; pick whichever produces less framework overhead during the analysis pass.
- Your storefront is heavily personalised — most pages are bypassed anyway; the simpler modes are fine.
Performance cost
Section titled “Performance cost”The field-diff is computed inside the entity-written event handler. For a single-product save, it adds sub-millisecond overhead. For bulk updates, the overhead scales linearly with the number of entities — usually negligible compared to the database write itself, but visible in worst-case profiles.
If the analysis becomes a bottleneck on very large imports, switch to Precise for the duration of the import and back to Smart afterwards.
Extending Smart
Section titled “Extending Smart”Smart’s field mapping lives in SmartInvalidationAnalyzer. To extend it from a custom plugin:
- Decorate
P2Lab\Cache\Service\SmartInvalidationAnalyzerwith your own implementation. - Override the
analyze<Entity>Change(array $changedFields): arraymethods to return your custom tag set for fields the plugin doesn’t know about.
The standard tag conventions are documented in Architecture.