Table of Contents

Image Caches

ImageSharp.Web caches processed output so that identical requests do not repeatedly decode, process, and re-encode the source image. The cache stores both the encoded bytes and metadata about the source and response so the middleware can detect stale entries and serve correct headers.

Think of the cache as derived output, not source-of-truth storage. It should be safe to clear and rebuild, but it must be configured carefully enough that all application instances agree on keys, freshness, and storage location.

How the Cache Works

For each processed request, the middleware:

  • builds a cache key from the request path plus the sanitized command collection;
  • hashes that key into a filesystem-safe cache name;
  • stores the encoded image plus metadata such as source last-write time, cache write time, content type, browser max-age, and content length;
  • reuses the cached result until the source changes or the cache entry ages beyond ImageSharpMiddlewareOptions.CacheMaxAge.

Default Physical Cache

PhysicalFileSystemCache is the default backend registered by AddImageSharp().

using SixLabors.ImageSharp.Web;
using SixLabors.ImageSharp.Web.Caching;

builder.Services.AddImageSharp()
    .Configure<PhysicalFileSystemCacheOptions>(options =>
    {
        options.CacheRootPath = "cache";
        options.CacheFolder = "imagesharp";
        options.CacheFolderDepth = 8;
    });

If your app does not define a web root, set CacheRootPath explicitly. Relative paths are resolved against the application content root.

Browser Lifetime Versus Backend Lifetime

ImageSharp.Web tracks two different lifetimes:

If the source provider supplies a source Cache-Control max-age, that value overrides BrowserMaxAge for the response.

Set browser lifetime based on how long clients may keep a response without revalidation. Set backend cache lifetime based on how long your server-side derived output should be trusted before checking the source again. Those are related, but they are not the same operational decision.

Cache Keys and Hashes

By default, ImageSharp.Web uses:

If you need cache entries to vary by host or some other request detail, swap the key implementation with SetCacheKey<T>() or SetCacheHash<T>():

using SixLabors.ImageSharp.Web;
using SixLabors.ImageSharp.Web.Caching;

builder.Services.AddImageSharp(options =>
{
    options.CacheHashLength = 16;
})
.SetCacheKey<UriAbsoluteLowerInvariantCacheKey>()
.SetCacheHash<SHA256CacheHash>();

Preserve the v1 Cache Layout

If you are migrating an older installation and want new requests to keep using the v1 cache naming layout, switch to LegacyV1CacheKey and keep the folder depth aligned with the hash length:

using SixLabors.ImageSharp.Web;
using SixLabors.ImageSharp.Web.Caching;

builder.Services.AddImageSharp(options =>
{
    options.CacheHashLength = 12;
})
.Configure<PhysicalFileSystemCacheOptions>(options =>
{
    options.CacheFolderDepth = 12;
})
.SetCacheKey<LegacyV1CacheKey>();

Azure Blob Storage Cache

Install the Azure provider package:

dotnet add package SixLabors.ImageSharp.Web.Providers.Azure

Then replace the default cache backend with SetCache<T>():

using Azure.Storage.Blobs.Models;
using SixLabors.ImageSharp.Web;
using SixLabors.ImageSharp.Web.Azure.Caching;

builder.Services.AddImageSharp()
    .Configure<AzureBlobStorageCacheOptions>(options =>
    {
        options.ConnectionString = builder.Configuration["Azure:ConnectionString"]!;
        options.ContainerName = "imagesharp-cache";
        options.CacheFolder = "processed";

        AzureBlobStorageCache.CreateIfNotExists(options, PublicAccessType.None);
    })
    .SetCache<AzureBlobStorageCache>();

Cached objects use the hashed request key as the blob name, and the cache metadata is stored in blob properties alongside the object.

AWS S3 Cache

Install the AWS provider package:

dotnet add package SixLabors.ImageSharp.Web.Providers.AWS

Then replace the default cache backend with SetCache<T>():

using Amazon.S3;
using SixLabors.ImageSharp.Web;
using SixLabors.ImageSharp.Web.AWS.Caching;

builder.Services.AddImageSharp()
    .Configure<AWSS3StorageCacheOptions>(options =>
    {
        options.BucketName = "imagesharp-cache";
        options.Region = "us-east-1";
        options.AccessKey = builder.Configuration["AWS:AccessKey"];
        options.AccessSecret = builder.Configuration["AWS:SecretKey"];
        options.CacheFolder = "processed";

        AWSS3StorageCache.CreateIfNotExists(options, S3CannedACL.Private);
    })
    .SetCache<AWSS3StorageCache>();

Cached objects use the hashed request key as the object key, and the response metadata needed by the middleware is stored with the object.

Practical Guidance

Treat the cache as derived output. It should be safe to clear and rebuild, but it must be separate from source storage so cleanup jobs cannot delete originals. In single-instance deployments a physical cache may be enough; in multi-instance deployments, use shared storage when all instances should reuse the same processed variants.

Cache lifetime has two audiences. Browser lifetime controls how long clients may reuse a response without coming back. Backend cache lifetime controls how long the server trusts a generated variant before checking source freshness. Those values should match source update frequency, CDN behavior, and the cost of regeneration.

If you customize cache keys, include every output-affecting request detail. Host, tenant, preset expansion, command values, and source path can all matter depending on the application. Monitor cache growth when public URLs expose many dimensions or quality values, because variant counts can grow faster than source image counts.