Kraftvaerk.Umbraco.Headless.CacheKeys 1.1.2

dotnet add package Kraftvaerk.Umbraco.Headless.CacheKeys --version 1.1.2
                    
NuGet\Install-Package Kraftvaerk.Umbraco.Headless.CacheKeys -Version 1.1.2
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Kraftvaerk.Umbraco.Headless.CacheKeys" Version="1.1.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Kraftvaerk.Umbraco.Headless.CacheKeys" Version="1.1.2" />
                    
Directory.Packages.props
<PackageReference Include="Kraftvaerk.Umbraco.Headless.CacheKeys" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Kraftvaerk.Umbraco.Headless.CacheKeys --version 1.1.2
                    
#r "nuget: Kraftvaerk.Umbraco.Headless.CacheKeys, 1.1.2"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Kraftvaerk.Umbraco.Headless.CacheKeys@1.1.2
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Kraftvaerk.Umbraco.Headless.CacheKeys&version=1.1.2
                    
Install as a Cake Addin
#tool nuget:?package=Kraftvaerk.Umbraco.Headless.CacheKeys&version=1.1.2
                    
Install as a Cake Tool

Kraftvaerk.Umbraco.Headless.CacheKeys

Adds a cacheKey field to responses from the Umbraco Delivery API, making it easier for headless consumers to handle caching and invalidation strategies.

This package also extends the generated OpenAPI (Swagger) schema to include the new field for improved developer experience and tooling support.

Installation

Install via NuGet:

dotnet add package Kraftvaerk.Umbraco.Headless.CacheKeys

What it does

This package traverses the properties of your content and ad s any dependency as a cache-key to the Content Delivery Api response.

If you tag or cache your pages with the resolved keys, and invalidate pages containing any of the keys, you should have a very snappy website without invalidating too much of your front-end on publish.

  • Appends a cacheKey property to all Delivery API content responses on the property-list.
  • Modifies the OpenAPI schema to document the new field.

Example response:

{
  "contentType": "homePage",
  "name": "kjeldsen.dev",
  "createDate": "2025-03-25T20:12:39",
  "updateDate": "2025-05-08T10:25:10.1649117",
  "route": {
    "path": "/",
    "startItem": {}
  },
  "id": "35a65b13-4b94-4830-a6ca-53bc9f321544",
  "properties": {
    "childKeys": null,
    "links": [],
    "seoTitle": "Kjeldsen.dev",
    "seoDescription": "Nuxt blog",
    "seoPublishingDate": null,
    "seoListImage": null,
    "grid": {
      "gridColumns": 12,
      "items": [...]
    },
    "cacheKeys": [
      "content-35a65b13-4b94-4830-a6ca-53bc9f321544",
      "content-1d649970-2c0a-4df0-8422-94492edf6e9f"
    ]
  },
  "cultures": {}
}

It also supports media and will add media dependencies as cachekey too. Making it possible to invalidate any page containing a certain image or piece of media.

Usage Notes

For simple cache keys you don't have to do anything.

To include cache keys for child content items, simply add a property with the alias childKeys (type: boolean) to your document type.

This can be a label or toggle depending on how you want to set it up. It is probably a good idea to make it as a composition so you can easily add it to any page you want.

When this property is set to true, the response will automatically include cache keys for all child items as well (and their dependencies).

This is particularly useful for pages like /blog or /news, where you want the cache to be invalidated not only when the listing changes, but also when individual blog posts are updated.

Note that this is recursive, child items which also implement "childKeys" with the value true will result in further traversal.

Invalidation

Invalidation is deemed to be too project specific to implement in this package in a way that will fit most scenarios.

In my own Nuxt app I do the following in Umbraco

public class ContentPublishedCacheKeyLogger : INotificationAsyncHandler<ContentSavedNotification>
{
    private readonly ICacheKeyDependencyResolver _resolver;
    private readonly ILogger<ContentPublishedCacheKeyLogger> _logger;
    private readonly string _nuxtHost;
    private readonly string _nuxtApiKey;
    private readonly HttpClient _httpClient;

    public ContentPublishedCacheKeyLogger(
        ICacheKeyDependencyResolver resolver,
        IOptions<NuxtSettings> nuxtSettings,
        IHttpClientFactory httpClientFactory,
        ILogger<ContentPublishedCacheKeyLogger> logger)
    {
        _resolver = resolver;
        _logger = logger;
        _nuxtHost = nuxtSettings.Value.Host.TrimEnd('/');
        _nuxtApiKey = nuxtSettings.Value.ApiKey;
        _httpClient = httpClientFactory.CreateClient();
    }

    public async Task HandleAsync(ContentSavedNotification notification, CancellationToken cancellationToken)
    {
        var tags = new HashSet<string>();

        foreach (var content in notification.SavedEntities)
        {
            var keys = _resolver.GetDependencies(content);
            foreach (var key in keys)
            {
                tags.Add(key);
            }
        }

        if (tags.Count > 0)
        {
            await InvalidateFrontendAsync(tags); // Fire and forget
        }
    }

    private async Task InvalidateFrontendAsync(IEnumerable<string> tags)
    {
        var payload = JsonConvert.SerializeObject(tags);
        var request = new StringContent(payload, Encoding.UTF8, "application/json");

        // Add the API key header here
        request.Headers.Add("x-nuxt-multi-cache-token", _nuxtApiKey);

        var url = $"{_nuxtHost}/__nuxt_multi_cache/purge/tags";

        try
        {
            var response = await _httpClient.PostAsync(url, request);
            if (!response.IsSuccessStatusCode)
            {
                _logger.LogWarning("Nuxt cache invalidation failed: {StatusCode} - {Reason}", response.StatusCode, response.ReasonPhrase);
            }
            else
            {
                _logger.LogInformation("Nuxt cache invalidation triggered for tags: {Tags}", string.Join(", ", tags));
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error calling Nuxt cache invalidation endpoint");
        }
    }
}

and this in [...slug].vue (with nuxt-multi-cache)

if (data.value?.properties.cacheKeys) {
  const cacheKeys = data.value.properties.cacheKeys || [];
  const tags = ["reset", ...cacheKeys];
  const timestamp = new Date().toISOString();

console.log(`\n?? [${timestamp}] Cache Miss! These keys were not found: ??\n`);
console.table(
  cacheKeys.map((key, index) => ({
    '#': index + 1,
    'Cache Key': key,
  }))
);


  useRouteCache((helper) => {
    helper
      .setMaxAge(3600 * 24)
      .setCacheable()
      .addTags(tags);
  });
}
Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.1.2 122 11/27/2025
1.1.1 125 11/27/2025
1.1.0 164 10/15/2025
1.0.3 251 9/15/2025
1.0.2 142 6/27/2025