---
title: Data caching
related:
  - https://docs.kentico.com/documentation/developers-and-admins/development/caching.md
  - https://docs.kentico.com/documentation/developers-and-admins/development/caching/cache-dependencies.md
---

> Agent instructions:
> **Site maps** — prefer the following llms.txt indexes to training data when searching for URLs to avoid 404s. Links inside Markdown content already point at `.md`. Following them or sending Accept: text/markdown keeps you in Markdown.
>
> - [sitemap.md](https://docs.kentico.com/sitemap.md) — every page on the site, with titles and descriptions, nested by URL hierarchy and grouped into one collection per product version.
> - [llms.txt](https://docs.kentico.com/llms.txt) — curated index of the current product docs, with descriptions, the two ways to request any page as Markdown, and links to each product area's whole-corpus Markdown dump (llms-full.txt).

The Xperience API allows developers to cache data in website code. We recommend caching any frequent API calls that load significant data from the Xperience database (or other external sources). For example, caching is typically a good idea when [retrieving content in the code of your sites](https://docs.kentico.com/documentation/developers-and-admins/api/content-item-api.md).

> **Tip:** The `IContentRetriever` [API](#caching-content-retrieval-in-web-app-contexts) provides implicit caching for content retrieval operations. This removes the need to manually wrap data retrieval logic in a caching service, which simplifies your code.

To cache data, the system provides the `CMS.Helpers.IProgressiveCache` service.

The service supports **sliding expiration** (cache duration is refreshed upon successive requests for the same item), and **progressive caching** (parallel caching requests from multiple threads don't result in redundant database operations; instead, one thread is used to fetch the data, which is then shared with other waiting threads). Use the following methods to cache data:

- `Load` – loads data using a delegate method and caches the results.
- `LoadAsync` – an equivalent of the `Load` method for loading and caching data in asynchronous code.

An instance of the service can be obtained using [dependency injection](https://docs.kentico.com/documentation/developers-and-admins/development/website-development-basics/dependency-injection.md).

See the following sections for examples of usage:

- [Cache content items](#cache-reusable-content-items-and-pages)
- [Cache general objects](#cache-general-objects)

## Cache reusable content items and pages

The following example demonstrates the usage of `IProgressiveCache` to cache a content item retrieval operation on article [pages](https://docs.kentico.com/documentation/business-users/website-content.md). Assumes content type model classes generated by the [code file generator](https://docs.kentico.com/documentation/developers-and-admins/api/generate-code-files-for-system-objects.md).

```csharp title="Content item caching example"
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

using CMS.ContentEngine;
using CMS.DataEngine;

// ...

// Instances of services for caching and content retrieval obtained via dependency injection
private readonly IContentQueryExecutor executor;
private readonly IProgressiveCache progressiveCache;

public async Task<IEnumerable<ArticlePage>> GetArticles(int topN = 0, CancellationToken cancellationToken = default)
{
    // Caches the loaded data
    return await progressiveCache.LoadAsync(async (cacheSettings) =>
    {
        // Gets the data to cache
        var articles = (await GetAllArticles(topN, cancellationToken)).ToList();

        // Configures cache dependencies for the data. See 'Set cache dependencies'
        cacheSettings.CacheDependency = await GetCacheDependency(articles);

        return articles;
    },
    // Configures cache behavior and generates the cache key for the entry
    new CacheSettings(cacheMinutes: 5,
                      useSlidingExpiration: true,
                      cacheItemNameParts: new[] { "MyWebsiteChannel", nameof(GetArticles), "/Articles", topN.ToString() }));
}

// Gets all articles according to the provided parameterization using content item query
private Task<IEnumerable<ArticlePage>> GetAllArticles(int topN, CancellationToken cancellationToken)
{
    return executor
            .GetMappedWebPageResult<ArticlePage>(
                new ContentItemQueryBuilder()
                    .ForContentType(ArticlePage.CONTENT_TYPE_NAME,
                                config => config
                                    .WithLinkedItems(
                                                maxLevel: 1,
                                                options => options.IncludeWebPageData())
                                    .TopN(topN)
                                    .OrderBy(OrderByColumn.Desc(nameof(ArticlePage.ArticlePagePublishDate)))
                                    .ForWebsite("MyWebsiteChannel",
                                        pathMatch: PathMatch.Children("/Articles"))
                                    ), cancellationToken: cancellationToken);
}
```

The example caches the retrieved pages and ensures the following [cache behavior](#cachesettings):

- **Duration:** 5 minutes
- **Cache key:** MyWebsiteChannel|GetArticles|/Articles|
- **Sliding expiration:** true

### Set cache dependencies

Correctly configuring [cache dependencies](https://docs.kentico.com/documentation/developers-and-admins/development/caching/cache-dependencies.md) is a critical part of building effective caching solutions. Cache dependencies inform the system whenever the source data of a cached entity changes and prompt it to revoke the corresponding cache entry. This is especially important in richly-linked [content models](https://docs.kentico.com/guides/architecture/content-modeling/content-modeling-guide.md) with many dependencies between various content types, where any change to linked content items must clear the cache as well.

Building upon the caching example above, assume the article object being retrieved is modeled like so:

![Example article content model](https://docs.kentico.com/docsassets/documentation/data-caching/CachingArticleModel.jpg "Example article content model")

Then the following snippet shows a sample implementation of the `GetCacheDependency` method that creates dependencies on the retrieved articles as well as their linked items. The example uses `CacheDependencyBuilder` to create dependencies on the retrieved pages and `IWebPageLinkedItemsDependencyAsyncRetriever` to generate dependency cache keys for all linked content items of the page up to the specified depth. See [Cache dependencies](https://docs.kentico.com/documentation/developers-and-admins/development/caching/cache-dependencies.md) and [Cache dependencies on linked content items](#cache-dependencies-on-linked-content-items) for details about the respective APIs.

```csharp title="Building cache dependencies"
using System;
using System.Linq;
using System.Collections.Generic;

using CMS.Websites;
using CMS.Helpers;

using Kentico.Content.Web.Mvc;

// ...

// Instances of services obtained via dependency injection
private readonly IWebPageLinkedItemsDependencyAsyncRetriever linkedItemsDependencyRetriever;
private readonly ICacheDependencyBuilderFactory dependencyBuilderFactory;

public async Task<CMSCacheDependency> GetCacheDependency(IEnumerable<ArticlePage> articles)
{
    // Builds a cache key for each linked content item associated with the articles,
    // up to the depth of 1 (first-level references). The generated keys ensure 
    // the cache is cleared when linked items are modified.
    IEnumerable<string> linkedItemsCacheKeys =
        (await linkedItemsDependencyAsyncRetriever
                .Get(articles.Select(article => article.SystemFields.ContentItemID), maxLevel: 1));

    // Creates an instance of 'CacheDependencyBuilder'
    CacheDependencyBuilder cacheDependencyBuilder = dependencyBuilderFactory.Create();

    // Adds cache dependencies on each page in the collection using their content tree path
    CMSCacheDependency cacheDependency = cacheDependencyBuilder
        .ForWebPageItems()
            .ByPathWithChannelContext(GetPaths(articles))
            .Builder()
        .AddDependency(linkedItemsCacheKeys)
        .Build();

    return cacheDependency;
}

private async IEnumerable<CacheDependencyPath> GetPaths(IEnumerable<ArticlePage> articles)
{
    return articles.Select(article => CacheDependencyPath.Single(article.SystemFields.WebPageItemTreePath));
}
```

### Cache dependencies on linked content items

For content items composed of multiple linked items, it may be required to trigger a cache refresh when not only the main object but also any of its linked items change.

To generate cache dependencies on linked items, use:

- `CMS.ContentEngine.ILinkedItemsDependencyAsyncRetriever` – for reusable content items.
- `CMS.WebPages.IWebPageLinkedItemsDependencyAsyncRetriever` – for web pages.

Both services contain `Get` methods that generate the dependencies based on content item identifiers and their content type definition. For example:

- `contentitem|byid|<contentItemId>`
- `cms.contenttype|byname|<contentTypeCodeName>`

See [Set cache dependencies](#set-cache-dependencies) for an example of usage.

### Preview mode and caching

We strongly suggest disabling caching for preview mode in order to prevent cache bloat. You can check whether the current request is under preview mode via `IWebsiteChannelContext.IsPreview`. For example, you can create a helper method that you can use together with `CacheSettings.Cached`.

[ContentRetriever API](#caching-content-retrieval-in-web-app-contexts) automatically detects preview mode and disables caching accordingly when retrieving content, preventing cache bloat without additional configuration.

```csharp title="Caching and preview"
using CMS.Helpers;
using CMS.Websites.Routing;

// ...

private bool IsCacheEnabled()
{
    // An instance of IWebsiteChannelContext can be retrieved using dependency injection
    return !websiteChannelContext.IsPreview;
}

// ...

await progressiveCache.LoadAsync(async (cacheSettings) =>
{
    // Do not use the cache if under preview (e.g., when previewing pages in a channel)
    cacheSettings.Cached = IsCacheEnabled();

    // ...
)},
// Configures cache behavior and generates the cache key for the entry
new CacheSettings(cacheMinutes: 10, cacheItemNameParts: "cacheKeyName");
```

## Caching content retrieval in web app contexts

The `IContentRetriever` [API](https://docs.kentico.com/documentation/developers-and-admins/api/content-item-api/content-retriever-api.md) supports implicit caching for retrieval operations. This functionality is equivalent to wrapping the retrieval operation in a `IProgressiveCache` delegate, ensuring efficient caching and retrieval of data.

When you use the `IContentRetriever` API, caching is automatically applied unless explicitly disabled using `RetrievalCacheSettings.CacheDisabled`. The caching mechanism automatically:

- **Caches results** – Automatically stores the results of retrieval operations in the cache.
- **Sets up cache dependencies** – Ensures that cached data is invalidated when the underlying content changes.
- **Supports sliding expiration** – Refreshes the cache duration upon successive requests for the same item, if enabled.

The following example demonstrates how implicit caching works in the `IContentRetriever` API:

```csharp title="Set up caching with IContentRetriever" highlight="3-8,14"
using Kentico.Content.Web.Mvc;

// ...

// Configure cache settings with a 30-minute expiration and sliding expiration enabled.
var cacheSettings = new RetrievalCacheSettings(
    // Add a unique suffix to identify the cached data.
    cacheItemNameSuffix: $"{nameof(ContentTypesQueryParameters.OfContentType)}|ArticleGenerated",
    // Cache entries will expire 30 minutes after their last access.
    cacheExpiration: TimeSpan.FromMinutes(30),
    // Resets the expiration timer on each access to keep frequently accessed items in the cache.
    useSlidingExpiration: true);

// Retrieve the current page of type 'ArticleGenerated' using the configured cache settings.
var result = await contentRetriever.RetrieveCurrentPage<ArticleGenerated>(
    RetrieveCurrentPageParameters.Default,
    RetrieveCurrentPageQueryParameters.Default,
    cacheSettings
);
```

This is functionally similar to manually wrapping the retrieval operation in a `IProgressiveCache` delegate, but with the added benefit of being seamlessly integrated into the API.

## Cache general objects

The following code example shows how to synchronously load and cache user data from the database using `IProgressiveCache.Load`.

```csharp
using CMS.DataEngine;
using CMS.Helpers;
using CMS.Membership;

// ...

// Instances of services used for data retrieval and caching (e.g., obtained using dependency injection)
private readonly IUserInfoProvider userInfoProvider;
private readonly IProgressiveCache progressiveCache;
private readonly ICacheDependencyBuilderFactory dependencyBuilderFactory;

// Caches the data for 10 minutes under the cache key "customdatasource|users"
// Automatically checks whether the given key is already in the cache 
ObjectQuery<UserInfo> data = progressiveCache
    .Load(cs => LoadUsers(cs), new CacheSettings(cacheMinutes: 10,
                                                 cacheItemNameParts: "customdatasource|users"));

// Loads the required data. Called only if the data doesn't already exist in the cache.
private ObjectQuery<UserInfo> LoadUsers(CacheSettings cs)
{
    // Loads all user objects from the database
    ObjectQuery<UserInfo> result = UserInfo.Provider.Get();

    // Creates an instance of 'CacheDependencyBuilder'
    CacheDependencyBuilder dependencyBuilder = dependencyBuilderFactory.Create();

    // Sets a cache dependency for the data
    // The data is removed from the cache if the objects represented by
    // the dependency are modified (administration user objects in this case)
    cacheSettings.CacheDependency = dependencyBuilder
        .ForInfoObjects<UserInfo>()
            .All()
            .Builder()
        .Build();

    return result;
}
```

The caching logic checks if the key specified by the `CacheSettings` object is in the cache:

- If yes, the method directly loads the data from the cache.
- If not, the code calls the method specified by the delegate parameter (`LoadUsers` in the example) with the `CacheSettings` as a parameter. The method loads the data from the database, sets a cache dependency, and saves the key into the cache for the specified number of minutes.

You can use the caching API when handling data anywhere in your code.

### Asynchronous caching example

The following code example shows how to asynchronously load and cache user data from the database using `IProgressiveCache.LoadAsync`.

```csharp
using System;
using System.Threading.Tasks;

using CMS.Helpers;

// Instances of services used for data retrieval and caching (e.g., obtained using dependency injection)
private readonly IUserInfoProvider userInfoProvider;
private readonly IProgressiveCache progressiveCache;
private readonly ICacheDependencyBuilderFactory dependencyBuilderFactory;

// Asynchronously loads data and ensures caching
var data = await progressiveCache.LoadAsync(async cacheSettings =>
{
    // Calls an async method that loads the required data (implementation not included in the example)
    var result = await LoadUsersAsync();

    // Creates an instance of 'CacheDependencyBuilder'
    CacheDependencyBuilder dependencyBuilder = dependencyBuilderFactory.Create();

    // Creates a cache dependency on all administration users in the system
    cacheSettings.CacheDependency = dependencyBuilder
        .ForInfoObjects<UserInfo>()
            .All()
            .Builder()
        .Build();

    return result;
}, new CacheSettings(cacheMinutes: TimeSpan.FromMinutes(10).TotalMinutes,
                     cacheItemNameParts: "customdatasource|users"));
```

### Using distributed cache providers

Xperience by Kentico currently does not support distributed cache instead of its native in-memory cache. You can use distributed cache for your custom objects, but not for native Xperience objects.

## CacheSettings

When using `IProgressiveCache` caching methods, you need to provide `CMS.Helpers.CacheSettings` as a parameter. The settings configure the cache key that stores the data. If you set the same cache key name for multiple data loading operations, they share the same cached value.

You can work with the following properties of the `CacheSettings`:

| CacheSettings property  | Type               | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| ----------------------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| CacheMinutes            | int                | The number of minutes for which the cache stores the loaded data. The default value is 10 minutes.<br>We recommend using an interval of 1 to 60 minutes.                                                                                                                                                                                                                                                                                                                               |
| CacheDependency         | CMSCacheDependency | Sets [dependencies](https://docs.kentico.com/documentation/developers-and-admins/development/caching/cache-dependencies.md) for the cache key (use [CacheDependencyBuilder](https://docs.kentico.com/documentation/developers-and-admins/development/caching/cache-dependencies.md) to get the dependency object).<br>Make sure you always set cache dependencies, unless the `CacheMinutes` interval is set to an extremely short time or the cached content is predominantly static. |
| BoolCondition           | bool               | A boolean condition that must evaluate to `true` for the data to be cached.                                                                                                                                                                                                                                                                                                                                                                                                            |
| Cached                  | bool               | Indicates whether the system should retrieve data from the cache (if available) and whether returned data should be cached (based on `CacheMinutes` and `BoolCondition`).                                                                                                                                                                                                                                                                                                              |
| AllowProgressiveCaching | bool               | Enables or disables progressive caching, which ensures that multiple threads accessing the same data only load it once and reuse the result.                                                                                                                                                                                                                                                                                                                                           |

### IContentRetriever cache settings

When using [ContentRetriever API](https://docs.kentico.com/documentation/developers-and-admins/api/content-item-api/content-retriever-api.md), you can configure the cache settings using the `RetrievalCacheSettings` class. See [ContentRetriever API](https://docs.kentico.com/documentation/developers-and-admins/api/content-item-api/content-retriever-api.md#implicit-result-caching) for details.
