What If You Didn’t Have to Invalidate the Cache?

Michał Cukierman

by Michał Cukierman
4 min read

continuous-materialization-header continuous-materialization-header

At adaptTo() 2026, we’ll show how continuous materialization changes the traditional request-and-cache model for AEM.

Caching is a fundamental part of AEM delivery architecture. Dispatcher keeps expensive rendering away from most requests, reduces load on Publish instances, and gives us a fast delivery path.

The difficult part starts when the inputs to a cached representation change. An author publishes a page, a shared component is updated, or data used to render many pages changes. The cached output may no longer represent the current source state, so we need a way to restore consistency.


Invalidation tells us what is no longer valid

AEM has several mechanisms for this. Publication can invalidate Dispatcher content, .stat files can invalidate larger parts of the content tree, TTLs can expire cached responses, and AEM as a Cloud Service adds CDN caching and purge mechanisms on top.

These mechanisms solve an important problem: they prevent known stale representations from being served indefinitely. They do not, however, produce the replacement representation.

After an entry has been invalidated, the next request normally causes the delivery stack to retrieve or render the current version again. The cycle is still based on request-time recovery:

Request and cache diagram

For most requests the cache removes the expensive work. After a change, some request has to bring the new representation back into the delivery path.

Cache warmup can reduce that first-request penalty. You can proactively request invalidated pages, prefetch known URLs, or run warming jobs after deployment or publication. But that introduces another mechanism that needs to know what changed, which URLs are affected, and when they should be requested. The cache is still rebuilt by simulating demand rather than by processing the source change itself.


What if change produced the replacement

Continuous materialization changes the trigger. Instead of waiting for a request to discover that a representation needs to be rebuilt, processing starts when an input changes.

The flow becomes:

continuous materialization

When the visitor requests the resource, the new state has already been produced and distributed. The request is not responsible for rebuilding it.

This is the important difference. Cache invalidation tells the system that existing derived state can no longer be trusted. Continuous materialization produces the new derived state as a consequence of the source change.


The dependency problem does not disappear

Consider a product change that affects 200 pages. Moving computation to change time only works if the system knows that those pages depend on the changed product.

The same applies to an AEM page that combines editorial content with data from a PIM or another system. We still need to define which inputs contribute to an output and which changes should cause that output to be recomputed.

Continuous materialization does not remove this problem. It makes those dependencies part of the processing model instead of relying on cache invalidation rules and later requests to restore the correct state.

In StreamX, source changes arrive as events. Processing services consume the changes relevant to them, maintain the state they need from their inputs, and produce derived outputs. Those outputs can be HTML pages, search documents, sitemap entries, product representations, or other delivery state.

The processing topology therefore describes both the dependency and what should happen when that dependency changes.


A multi-source page makes the difference easier to see

Take a product page where editorial content comes from AEM, product attributes come from a PIM, and categorization comes from another system.

In a request-driven architecture, those systems can participate directly in rendering, or their results can be cached. If the result is cached, the architecture needs a strategy for deciding when that representation has become stale and how it should be rebuilt.

With continuous materialization, each source publishes its changes independently. The processing layer maintains the state required to create the resulting page.

A publication in AEM can produce a new page representation. A product update can recompute representations that depend on that product. An unpublish can remove an output from delivery.

The visitor does not trigger integration between AEM, the PIM, and the other systems. That integration already happened when their state changed.


Moving work to change time creates different engineering problems

An event-driven system still has to deal with ordering, failures, retries, duplicate events, and independently changing sources. Those problems do not disappear because the processing happens before the request.

Identity and ordering therefore matter. Processing needs to distinguish resources, maintain the current state for them, and avoid letting an older change overwrite a newer one.

Failure handling also moves out of the request path. A failed processing step can be retried without making a visitor responsible for triggering the same work again.

This also changes the effect of a source-system outage. If AEM becomes unavailable after its latest changes have been processed, the last materialized state is already available in the delivery layer. There are no new AEM changes to process while it is offline, but delivery does not require AEM to be available.

When AEM comes back and starts producing changes again, processing continues from there. Content production and content delivery no longer have to fail together.


Are we just moving cache invalidation somewhere else?

We are moving complexity, but not cache invalidation itself.

We still need dependency information. We still maintain derived state, and we still have distributed-system concerns around consistency and failure.

The difference is the operation performed after a source change.

With cache invalidation, we identify derived state that should no longer be used and remove or expire it. A later request causes the replacement state to be obtained.

With continuous materialization, we identify the outputs affected by the change and produce their replacement state immediately.

The problem changes from:

What should I invalidate so a future request eventually receives the correct result?

to:

Which outputs depend on this change, and what state should this change produce?

For systems where those dependencies can be defined, the second model maps more directly to the underlying data relationship. It also makes processing independent of visitor traffic.


This does not mean caching disappears

Caching is still useful. Immutable assets, browser caches, CDN transport caching, and versioned JavaScript or CSS are obvious examples.

The architectural question is narrower: does a cache need to be the mechanism that separates expensive source systems from requests while also keeping dynamically derived public state correct?

For state that can be prepared before demand arrives, it does not.

Pages, product representations, search documents, navigation structures, feeds, and sitemaps can all be computed when their inputs change. Authentication, account state, payments, transactions, and other user-specific decisions still belong at request time.

The goal is not to move everything out of the request path. It is to stop doing predictable work there when the system already had enough information to do it earlier.


A smaller request path

Once rendering and source integration happen at change time, the delivery architecture becomes simpler.

AEM manages content. Other systems manage their domains. StreamX processes their changes and continuously produces the state required for delivery.

The request path then becomes:

continuous materilazation

We’re taking this to adaptTo() 2026

At adaptTo() 2026, Marek Czajkowski and Paweł Sobolewski will take this model apart using an AEM architecture and show it running rather than stopping at the diagram.

If cache invalidation has started to feel like an architecture of its own in your AEM environment, come find us in Berlin.

adaptTo() 2026
Berlin, Germany
28-30 September, 2026

From Cache Invalidation to Continuous Materialization

Session date and time:
29th September
@ 15:20 CEST