In this tutorial, you will learn how the frontend Episerver cache works. When you query the CMS, your sites performance is not impacted as the data is queried from a cache rather than the database. Using a frontend cache is the main reason why the Episerver API works so quickly. When we build large scale applications that get large numbers of traffic, it is important to understand how and when EPiServer caches data to ensure your website runs in the most efficient manner. To learn this secret knowledge, read on 🔥🔥🔥

Frontend Cache

The object cache is built on top of the ASP.NET runtime cache. As covered in Why are Pages and Blocks Returned From The Episerver API Read-Only?, the API only returns read-only objects for better performance. This mechanism enhances scalability, as multiple threads can read the same data.

When you query the CMS for content you will be using the IContentRepositoy and the Get<T>() method. Get<T>() takes a ContentReference and returns the related CMS object. On the first request, the API calls the database (as the cache is empty) and creates an in-memory representation of the requested object. After the object has been returned, it will be placed in the page cache using a unique cache key. From that point forward, until the cache expires, that object will be served from memory. By reducing the number of database requests, performance is improved. There are several edge cases where the API will not cache your objects:

  • If the WorkId in the ContentReference is included, the cache will be bypassed. As long as you want to access the latest version the API will use the cached object. When you want to work with a specific version of a page (by setting the WorkId) the API will make a call to the database.

The need to work with older versions of your pages and block happens very rarely so it works out quite well. Personally, whenever I have needed to access older versions of a page in code, for example, it has always been in some type of back-end admin plug-in where the feature is used rarely, meaning performance isn't as big a deal.

  • When you are viewing a page in the editor it will not be cached. This happens because when Episerver renders a page in edit mode' it does not use a read-only version. Instead, it uses a writable version, to allow content editors to update a page/block via the editor.

When an item is cached, it will be set to a default expiration period of 12 hours. This value is the out of the box setting, however, you are free to set this to any value you want. To change the timeout period, add an entry called pageCacheSlidingExpiration in your applicationSetting in the web.config. To set the cache timeout to an hour, your setting would look like this:

GetChildren()

If you need to query the CMS for a collection of pages, the caching works slightly differently. Episerver does not cache the page tree hierarchy/content structure directly. Behind the scenes, the page tree is never stored in one large collection. The results of GetChildren() are cached in an individual collection. When GetChilden<>() is called, it will look in the cache for a collection of ContentReferences. The cache stores a list of references and not the objects themselves.

If the cache is empty, the API will query the database and store the items individually as well as cache of how the pages are related. The API will then fetch each item from the list of content references and add them to a PageDataCollection . GetChildren<T>() will then return this collection to the caller. The API retrieves the page objects using the Get<T>() method. This API checks if the key is in the cache already, otherwise it goes off to the database to retrieve it and then add it to the cache.

If a content editor updates a page or a block, for instance, as long as the parent does not change, the collection of contents references stored by GetChildren<>() does not need to be updated and can still live in cache unmodified. Only the item that got updated needs to be refreshed.

FindPagesWithCriteria() and FindAllPagesWithCriteria()

I've talked previously about FindPagesWithCriteria, in FindPagesWithCriteria: How to search for pages within Episerver. As this is another API that queries the CMS so let's see how this process caches things.

The mechanics of FindPagesWithCriteria is kind of similar to GetChildren() to get the cached results. The database is queried to get a collection of content references. The API then fetches each page individual object usingGet()`

The main difference between GetChildren<T>() and FindPagesWithCriteria() is that the collection of ContentReferences created in FindPagesWithCriteria is not cached. If you think about it, this makes sense. You would normally only consider using FindPagesWithCriteria when building something like a site search. In these instances, each search query will be different, so caching the content collection list doesn't make a lot of sense.

My recommendation is to always favour GetChildren<T>() as it uses the cache. FindPagesWithCriteria() is more performance-intensive. If you need to query a lot of things from the whole of the page tree, it has been proven to be quicker than constantly having to iterate over everything using GetChildren<T>().

Another handy tip when designing your site is that you should never try to cache the content objects yourself in memory. Attempting to cache PageData objects yourself will only result in complications, like worrying about how you to invalidate the cache when content editors update content.

If you think about it, this makes sense. You would normally only consider using FindPagesWithCriteria when you need to query items that may live anywhere in the page tree, for example, a site search. In these instances, a search might change regularly, so caching the content collection list doesn't make a lot of sense.

My recommendation is to always favour GetChildren<T>() as it uses the cache. FindPagesWithCriteria() is more performance-intensive but if you need to query a lot of things from the whole of the page tree then it is quicker than constantly having to iterate over everything using GetChildren<T>().

Another handy tip when designing your site is that you should never try to cache the content objects yourself in memory. Attempting to cache PageData objects yourself will only result in complications like worrying about how you to invalidate the cache when content editors update content.


Understanding the cache is an important part of mastering the CMS. You are now one step closer to Episerver master status. Happy Coding 🤘