Problem Statement:
Cache all the experience fragments in AEM under a common or shared location on the dispatcher to load dynamically whenever the XF page is activated.
Improve initial page load performance on subsequent requests on the same or similar pages.
Introduction:
The purpose of the module presented here is to replace dynamically generated components (eg. current time or foreign exchange rates) with server-side include tags (eg. SSI or ESI). Therefore the dispatcher is able to cache the whole page but dynamic components are generated and included with every request. Components to include are chosen in filter configuration using resourceType attribute.
When the filter intercepts a request for a component with a given resourceType, it’ll return a server-side include tag (eg. <!–#include virtual=”/path/to/resource” –> for Apache server). However, the path is extended by a new selector (XF by default). This is required because the filter has to know when to return actual content.
Components don’t have to be modified in order to use this module (or even be aware of its existence). It’s a servlet filter, installed as an OSGi bundle and it can be enabled, disabled, or reconfigured without touching the CQ installation.
Flow diagram on the approach:
As part of this implementation, we are trying to cache all the content paths i.e., /var/www/html/publish/content/{site-structire} and experience fragments at different paths like /var/www/html/publish/content/experience-fragment/{site-structure} as shown below:

Create a wrapper component as shown below:
- If Container then create a wrapper container component sling:resourceSupertype = core/wcm/components/container/v1/container
- If Layout container then create wrapper responsivegrid component sling:resourceSupertype = wcm/foundation/components/responsivegrid

Update all the XF pages container/layout container components as shown below:
Update only the first container resourcetype under root node to the newly created wrapper component

Update the XF template as shown below:
Update both initial content and structure content, only the first container resourcetype under the root node to the newly created wrapper component

Sling Dynamic Include:
Configure the Sling dynamic as per the documentation provided here: https://experienceleague.adobe.com/docs/experience-manager-learn/foundation/development/set-up-sling-dynamic-include.html?lang=en
Configure Sling dynamic configuration as shown below:

Add filter to Dispatcher filter:
/0190 { /type "allow" /extension "html" /selectors "xf" /path "/content/experience-fragments/*" }
Add rules to cache XF selector as shown below:
/0013 {
/glob "*.xf.html*"
/type "allow"
}
Do not add cache deny rule
Once the page is loaded you will be seeing following SDI include message as shown below on the publisher:

SDI loading on dispatcher port 8080

You can verify cache folder for results:

If SDI includes path appends resourcetype, then clone the SDI repo and update the code as shown below:

Open the IncludeTagFilter.java as shown below and update the code at synthetic variable to false:

Run mvn clean install to generate the new jar file and install directly on the publish server or include the external jar dependency on maven
Advantages of caching Experience fragment at common or shared location:
- Increases initial page load – response time based on the number of XF on the page
- Decreases the Dispatcher cache size – based on the number of XF components on the page
- Improves overall page load time
- Better debugging SDI functionality – whenever the XF page is updated and published it removes from the cache and on a new page request a new cache is created and used on subsequent requests
- Decreases CPU utilization
Credits: I was able to finish this blog with help of my friend

Hi Kiran,
Really good article!
What would the approach be if you have an extra layer of CDN caching above the dispatcher. Akamai for example.
Could you walk through the full process on how it would work?
LikeLike
You can go with same approach but instead of caching at SSI (dispatcher level) you can use ESI caching
And there are many articles on how to use SDI with ESI
But only difference is instead of denying cache just allow it to cache I hope this should work but let me if it’s not working 🙂
LikeLike
Hi Kiran,
Really good article!
What would the approach be if you have an extra layer of CDN caching above the dispatcher. Akamai for example.
Could you walk through the full process on how it would work?
LikeLike
Hi Kiran,
Very helpful article.
Do you know why would need to set the synthetic variable as false? Why is responsive grid identified as a synthetic resource?
LikeLike
I think you should try this question on your local it takes 10-15min 🙂 and you will figure it out the answers
LikeLike
I had the same issue and I ended up doing the same fix as setting synthetic as false. But I know this happens as the resource Responsive grid is identified as synthetic by dispatcher which causes the synthetic property to be true. But that is what I am not able to understand, why does only dispatcher identify that as synthetic resource(TemplatedResorceImpl)
LikeLike
For some reason if resource super type points to outside current repo it considers it has synthetic
LikeLike
I tried replacing layout container with container component, there is no issue at all. It only happens with layout container. I believe this may be the reason:
https://github.com/adobe/aem-core-wcm-components/issues/999
as I made this change to responsive grid and it started working fine, responsive grip gets identified as jcrresource by dispatcher after I made the change.
But I am not entirely sure what causes it. its quite tricky.
LikeLike
Interesting 🤔
LikeLike
Hi I have tried this approach in my local env for Header EF (header data is coming from API not frequent changes) Header EF is not getting cached and EF is showing in publisher not in dispatcher any help ?
LikeLike
Setup dispatcher in local and debug the logs
LikeLike