---
title: Azure Blob storage
---

> 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).

Xperience by Kentico supports file system providers that allow you to map parts of the file system to [Microsoft Azure Blob Storage](https://azure.microsoft.com/en-us/products/storage/blobs/). You can use Blob storage when:

- [Deploying Xperience projects to the SaaS environment](https://docs.kentico.com/documentation/developers-and-admins/deployment/deploy-to-the-saas-environment.md)
- [Deploying to private cloud](https://docs.kentico.com/documentation/developers-and-admins/deployment/deploy-to-private-cloud.md)
- You need to store parts of the application file system in a shared storage. For example, shared storage is a requirement for all [scaled](https://docs.kentico.com/documentation/developers-and-admins/configuration/auto-scaling-support.md) Xperience deployments.

Blob storage is particularly suitable for storing content item assets, and all other [unmanaged binary files](https://docs.kentico.com/guides/architecture/content-modeling/content-modeling-guide/store-files.md) referenced by the Xperience application. Some application deployment environments, like [Azure Web Apps](https://azure.microsoft.com/en-us/products/app-service/web/) for example, do not guarantee a persistent file system for files created outside of the original deployment package. Therefore, if Azure needs to recycle the application due to rolling infrastructure updates or unexpected outages, all but the image with the original deployment is lost. Blob storage does not suffer from these limitations, as the infrastructure ensures redundancy in case of an outage.

Follow the instructions on this page to create Azure Blob storage providers for:

- [projects deployed to the SaaS environment](#azure-blob-storage-for-kenticos-saas)
- [private cloud deployments](#azure-blob-storage-for-private-cloud-deployments)

> **Info:** **File name case**
>
> Unlike regular file systems (NTFS, VFAT), Azure Blob storage is case-sensitive. To ensure consistent behavior, Xperience automatically converts all file and folder names to lowercase when processing files on Azure storage.

## Media library files in Azure Blob storage

> **Note:** **Media libraries will be removed**
>
> Support for media libraries ended on 24 July, 2026. The feature and its associated APIs will be removed in two steps:
>
> - **August 2026** Refresh – the feature was hidden in the admin UI for projects that have no media libraries.
> - **September 2026** Refresh – the feature and all associated APIs will be fully removed.
>
> Before mapping media library files to the [Microsoft Azure Blob Storage](https://azure.microsoft.com/en-us/products/storage/blobs/), consider migrating media libraries and mapping content item assets instead. See [Media library migration](https://docs.kentico.com/guides/architecture/media-libraries-migration-guidance.md) for instructions on how to migrate your media library files to [Content hub](https://docs.kentico.com/documentation/business-users/content-hub.md).

Media library files stored in Azure Blob storage have the following limitations:

- **Storing a large number (thousands) of media library files in a single media library can significantly affect the performance and user experience of the [Media libraries](https://docs.kentico.com/documentation/business-users/media-libraries/create-media-libraries.md) application.**
  - We recommend structuring media library files into multiple media libraries and storing at most 100 files in a single media library folder.
- Mapping subfolders of media libraries is not supported. You can map either the directory containing the media libraries (**\~/assets/media**), or individual media libraries (**\~/assets/media/**).
- The system's automatic clearing of files from the server-side cache does not work for files stored in an external storage. If you modify a media file, the website may still display the old version until the cache expires (unless you manually clear the application's cache). See also: [File caching](https://docs.kentico.com/documentation/developers-and-admins/development/caching/file-caching.md).

## Azure Blob storage for Kentico's SaaS

When developing an Xperience application that you want to [deploy to the SaaS environment](https://docs.kentico.com/documentation/developers-and-admins/deployment/deploy-to-the-saas-environment.md), use the [storage path mapping](https://docs.kentico.com/documentation/developers-and-admins/api/files-api-and-cms-io/file-system-providers/storage-path-mapping.md) system to route application files to Azure Blob Storage.

Azure Blob storage is part of your [Xperience by Kentico SaaS subscription](https://docs.kentico.com/documentation/developers-and-admins/installation/licenses.md#licensing-xperience-by-kentico-saas) and is used when deploying projects to the SaaS environment, as storing persistent data alongside Xperience application binaries deployed in [Azure App Service](https://docs.microsoft.com/en-us/azure/app-service/overview) is not recommended.

> **Info:** **Managed and unmanaged data**
>
> Only data that is not handled by the [CI/CD features](https://docs.kentico.com/documentation/developers-and-admins/ci-cd/reference-ci-cd-object-types.md) and is stored outside of the Xperience database needs to be deployed to the Azure Blob Storage.
>
> - Media library metadata is stored in the Xperience database, only the media library (binary) files are deployed.
> - Files stored in the content item asset fields do not need to be deployed as they are handled by CI/CD.

### Default Kentico-managed Azure Blob storage configuration

[Projects](https://docs.kentico.com/documentation/developers-and-admins/installation.md#create-a-project) created with the `--cloud` parameter include `AddXperienceCloudStoragePathMapping()` in `Program.cs` and the **Export-DeploymentPackage.ps1** deployment script. Xperience provides Azure Blob storage with the required accounts as part of every subscription.

The default configuration automatically maps all system paths based on the detected environment:

- **Cloud environments** (QA, UAT, Custom, Staging, Production) – all `SharedPersistent` paths (content item assets, media libraries, AIRA images, files uploaded via the _Upload file_ [form component](https://docs.kentico.com/documentation/developers-and-admins/development/builders/form-builder/reference-form-builder-components.md)) are mapped to Azure Blob Storage. The default container name is _default_.
- **Local development** – media library files are mapped to a local directory (**\~/$StorageAssets/default/assets/media**) so they can be included in the [deployment package](https://docs.kentico.com/documentation/developers-and-admins/deployment/deploy-to-the-saas-environment.md#deploy-with-a-deployment-package).

All system paths are registered automatically by Xperience modules. See [System-registered paths](https://docs.kentico.com/documentation/developers-and-admins/api/files-api-and-cms-io/file-system-providers/storage-path-mapping.md#system-registered-paths) for the full list.

### Customize the storage path mapping

To use a different container name or multiple containers for different paths, configure the options callback in `Program.cs`. The following table lists all available options:







```csharp title="Program.cs – custom container configuration"
using CMS.IO.Extensions;
using Kentico.Xperience.Cloud;

builder.Services.AddXperienceCloudStoragePathMapping(options =>
{
    // Set the default container name (default value is "default")
    options.ContainerName = "default";

    // Use a different container for specific paths
    options.ConfigureContainerForPath = (registration, setup) =>
    {
        if (registration.IsMediaLibraryPath())
        {
            setup.ContainerName = "media-files";
        }
    };
});
```

With this setup, media library files are stored in the `media-files` Azure Blob container in cloud environments and under `$StorageAssets/media-files/` in local development. All other paths use the `default` container (or `$StorageAssets/default/` locally).

> **Warning:** **Changing container names does not migrate existing data**
>
> Reconfiguring `ContainerName` or `ConfigureContainerForPath` does not automatically move files between containers. Any files already stored under the previous container name remain there and become inaccessible to the application once the mapping changes, which can lead to missing or broken binary data.

Use container names conforming to [Azure Blob storage container naming requirements](https://docs.microsoft.com/en-us/rest/api/storageservices/naming-and-referencing-containers--blobs--and-metadata#container-names).

> **Info:** Containers do not need to have an existing folder in the storage assets root folder, but need to have a valid mapping in your application – Xperience automatically ensures that the folder structure gets created in Azure Blob storage when your application tries to access those folders.
>
> Containers in deployment environments are isolated. You can map folders in different environments to containers with identical names.

If your application stores files in custom directories beyond what modules register, register them before the mapping call. See [Register custom paths](https://docs.kentico.com/documentation/developers-and-admins/api/files-api-and-cms-io/file-system-providers/storage-path-mapping.md#register-custom-paths).

> **Info:** **Custom mapping module approach**
>
> `AddXperienceCloudStoragePathMapping()` is a smart default designed to cover standard SaaS deployments. If its options don't meet your requirements – for example, you need advanced per-environment logic, non-standard authentication, or highly specific provider configuration – you can implement a custom mapping module instead. See [Custom file system providers](https://docs.kentico.com/documentation/developers-and-admins/api/files-api-and-cms-io/file-system-providers/custom-file-system-providers.md) for instructions.

### Migrate from StorageInitializationModule

Prior to version 31.6.0, SaaS projects configured storage path mapping using a custom `StorageInitializationModule` class (typically **StorageInitializationModule.cs**). This module manually created `AzureStorageProvider` instances, called `StorageHelper.MapStoragePath()` for each path, and branched on the hosting environment.

This module is replaced by a single `AddXperienceCloudStoragePathMapping()` call in `Program.cs`. Platform modules now register their own paths automatically – the application only declares its hosting model. See [Storage path mapping](https://docs.kentico.com/documentation/developers-and-admins/api/files-api-and-cms-io/file-system-providers/storage-path-mapping.md) for details on how the new system works.

If your project still uses a `StorageInitializationModule`, migrate to the new approach. For most common cases, the entire module collapses to:

```csharp title="Program.cs"
builder.Services.AddXperienceCloudStoragePathMapping();
```

Projects with custom container names, per-path overrides, or custom paths require additional configuration – see [Customize the storage path mapping](#customize-the-storage-path-mapping) and [Register custom paths](https://docs.kentico.com/documentation/developers-and-admins/api/files-api-and-cms-io/file-system-providers/storage-path-mapping.md#register-custom-paths).

Kentico provides a [migrate-storage-module-guide.md](https://docs.kentico.com/docsassets/documentation/azure-blob-storage/migrate-storage-module-guide.md) as a downloadable Markdown file that can be used as input for an AI coding agent (such as GitHub Copilot, Cursor, or similar). The guide covers all migration scenarios, including complex cases like per-path container overrides and retained modules for inexpressible mappings.

> **Warning:** **AI-assisted migration limitations**
>
> AI-generated code may contain errors. You are responsible for validating all changes and ensuring correctness. All changes must be tested in every deployment environment (local development, QA, UAT, production), as each environment may have different storage configurations.

## Azure Blob storage for private cloud deployments

To map parts of the file system to Azure Blob storage when deploying to [private cloud](https://docs.kentico.com/documentation/developers-and-admins/deployment/deploy-to-private-cloud.md), use the [storage path mapping](https://docs.kentico.com/documentation/developers-and-admins/api/files-api-and-cms-io/file-system-providers/storage-path-mapping.md) system.

### Recommendations

1. **Use separate [Azure Blob storage containers](https://docs.microsoft.com/en-us/azure/storage/blobs/storage-quickstart-blobs-portal) for each deployment environment for the same project (for example, production and testing environments)**. Such environments often contain identically named files that overwrite each other. To avoid collisions, use different container names per environment.
2. **Use HTTPS to connect to Azure Blob Storage accounts** (this behavior can be enabled via the [Security transfer required](https://docs.microsoft.com/en-us/azure/storage/common/storage-require-secure-transfer) setting available in the [Azure portal](https://portal.azure.com)). Xperience is by default configured to use HTTPS with Azure Blob Storage.
   - If you need to use HTTP (for example because of storage accounts supporting only unencrypted (HTTP) connections), include the  [ CMSAzureBlobEndPoint ](#optional-application-settings-for-azure-storage) configuration key in your application's configuration file. Set the value of the key to the full endpoint URL of the external storage account and explicitly specify the _HTTP_ protocol:

     ```json title="appsettings.json"
     {
     ...

         "CMSAzureBlobEndPoint": "http://_StorageAccountName_.blob.core.windows.net"
     }
     ```

### Set up storage mapping

1. Choose your authentication method. See [Authentication methods for Azure Blob storage](#authentication-methods-for-azure-blob-storage) for detailed configuration options.

2. Add the **Kentico.Xperience.AzureStorage** NuGet package to your project.

3. Call `AddAppServiceStoragePathMapping()` in `Program.cs`:

   ```csharp title="Program.cs"
   using Kentico.Xperience.AzureStorage;

   var builder = WebApplication.CreateBuilder(args);

   builder.Services.AddAppServiceStoragePathMapping(options =>
   {
       // Disable mapping in local development to avoid connecting to Azure
       options.IsMappingEnabled = !builder.Environment.IsDevelopment();
   });
   ```

   This maps all registered `SharedPersistent` paths to Azure Blob Storage (default container: _cmsstorage_) and `SharedTemp` paths to a shared file system.

   > **Warning:** Calling `AddAppServiceStoragePathMapping()` activates storage mapping **unconditionally** – there is no automatic environment detection. If you call this method without setting `IsMappingEnabled`, Azure Blob storage is active in all environments, including local development.
   >
   > Test your configuration in every environment before going to production. A mapping that compiles correctly may behave differently depending on Azure credentials and container availability.

   > **Info:** **Custom mapping module approach**
   >
   > `AddAppServiceStoragePathMapping()` is a smart default designed to cover standard Azure App Service deployments. If its options don't meet your requirements – for example, you need advanced per-environment logic, non-standard authentication, or highly specific provider configuration – you can implement a custom mapping module instead. See [Custom file system providers](https://docs.kentico.com/documentation/developers-and-admins/api/files-api-and-cms-io/file-system-providers/custom-file-system-providers.md) for instructions.

4. _(Optional)_ Set [Optional application settings for Azure storage](#optional-application-settings-for-azure-storage).

If your application stores files in custom directories, register them before the mapping call. See [Register custom paths](https://docs.kentico.com/documentation/developers-and-admins/api/files-api-and-cms-io/file-system-providers/storage-path-mapping.md#register-custom-paths).

### Configure private cloud mapping options

Pass an options callback to `AddAppServiceStoragePathMapping()` to customize the mapping:







The following example routes media library files and form file attachments to dedicated Azure Blob containers:

```csharp title="Program.cs – per-path container overrides"
using CMS.IO;
using CMS.IO.Extensions;
using Kentico.Xperience.AzureStorage;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddAppServiceStoragePathMapping(options =>
{
    options.IsMappingEnabled = !builder.Environment.IsDevelopment();
    options.ContainerName = "cmsstorage";

    options.CreateProviderForPath = (PathRegistration pathRegistration) =>
    {
        if (pathRegistration.IsMediaLibraryPath())
        {
            return AzureStorageProvider.Create("media-files");
        }

        if (pathRegistration.IsBizFormFilesPath())
        {
            return AzureStorageProvider.Create("form-submissions", publicExternalFolderObject: false);
        }

        // Return null to use the default provider for other paths
        return null;
    };
});
```

### Optional application settings for Azure storage

| Key                     | Description                                                                                                                                                                                                                                                                                                                          |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| CMSAzureTempPath        | The system uses the specified folder to store temporary files on a local disk, for example when transferring large files to or from the storage account.<br>If not set, the system creates and uses an **\~/AzureTemp** directory in the project's root.<br>`"CMSAzureTempPath": "C:\\AzureTemp"`                                    |
| CMSAzureCachePath       | Specifies a folder on a local disk where files requested from the storage account are cached. This helps minimize the amount of blob storage operations, which saves time and resources.<br>If not set, the system creates and uses an **\~/AzureCache** directory in the project's root.<br>`"CMSAzureCachePath": "C:\\AzureCache"` |
| CMSAzureBlobEndPoint    | Sets the endpoint used for the connection to the blob service of the specified storage account. If you wish to use the default endpoint, remove the setting completely from the appropriate files.<br>`"CMSAzureBlobEndPoint": "http://127.0.0.1:10000/devaccount"`                                                                  |
| CMSAzurePublicContainer | Indicates if the blob container used to store the application's files is public. If true, it will be possible to access files directly through the URL of the appropriate blob service, for example:<br>**https://.blob.core.windows.net/media/imagelibrary/logo.png**<br>`"CMSAzurePublicContainer": true`                          |
| CMSDownloadBlobTimeout  | Specifies the timeout interval in minutes for importing files from Azure Blob storage into Xperience.<br>The default is **1.5 minutes**. Increase the interval if you encounter problems when importing large files (2GB+).<br>`"CMSDownloadBlobTimeout": "5"`                                                                       |

### Authentication methods for Azure Blob storage

For private cloud deployments, Xperience supports two authentication methods for Azure Blob storage connections:

- **Shared key authentication** – Uses the storage account name and access key.
- **Managed identity authentication** – Uses Microsoft Entra authentication with [managed identities](https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/overview) . This is the recommended approach for enhanced security as it eliminates the need to store sensitive access keys in your application configuration.

> **Info:** **Managed identity benefits**
>
> Managed identity authentication provides several security advantages:
>
> - No need to store storage account keys in your application configuration
> - Automatic credential rotation handled by Azure
> - Fine-grained access control using Azure RBAC (Role-Based Access Control)
> - Reduced risk of credential exposure

#### Shared key authentication

Specify the storage account name and primary access key in your application configuration file (_appsettings.json_ by default).

1. Open the [Azure Management Portal](https://portal.azure.com).
2. Open **Storage accounts**.
3. Select your storage.
4. Switch to the **Access keys** tab.
5. Use the **Storage account name** and one of the provided access key values.

   ```json title="appsettings.json"
   {
       "CMSAzureAccountName": "StorageAccountName",
       "CMSAzureSharedKey": "PrimaryAccessKey"
   }
   ```

#### Managed identity authentication

Configure managed identity authentication using Microsoft Entra ID. This method provides enhanced security by eliminating the need to store access keys.

1. Set up managed identity in Azure:
   1. Enable managed identity for your Azure resources. See the [Azure managed identities documentation](https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/).
   2. Grant the managed identity appropriate roles and permissions to your storage account:

      - Role: **Storage Blob Data Owner**
      - This [built-in role](https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles/storage#storage-blob-data-owner) includes all necessary permissions for Xperience Azure Storage operations.
      - _**—OR—**_
      - Role: **Storage Blob Data Contributor**
      - With additional permissions:
        - `Microsoft.Storage/storageAccounts/blobServices/containers/getAcl/action` ([Get Container ACL](https://learn.microsoft.com/en-us/rest/api/storageservices/get-container-acl))
        - `Microsoft.Storage/storageAccounts/blobServices/containers/setAcl/action` ([Set Container ACL](https://learn.microsoft.com/en-us/rest/api/storageservices/set-container-acl))
      - The [Storage Blob Data Contributor role](https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles/storage#storage-blob-data-contributor) provides blob read/write access but requires additional container ACL permissions for full functionality. Use this configuration to enforce the principle of least privilege.

2. Configure storage account details in your application configuration:

   ```json title="appsettings.json"
   {
       "CMSAzureAccountName": "StorageAccountName"
   }
   ```

3. Configure managed identity authentication in your application startup:

   ```csharp title="Program.cs"
   using Azure.Identity;
   using Kentico.Xperience.AzureStorage;

   var builder = WebApplication.CreateBuilder(args);

   // Configure managed identity for Azure Storage
   builder.Services.AddAzureStorageCredential(serviceProvider =>
   {
       // For user-assigned managed identity, specify the client ID
       return new ManagedIdentityCredential("your-user-assigned-identity-client-id");
       
       // For system-assigned managed identity, use default constructor.
       // Note that for system-assigned identitites to work the connected
       // application must be deployed in Azure as well.
       return new ManagedIdentityCredential();
       
       // For DEVELOPMENT environments, you can also return
       // DefaultAzureCredential for automatic credential discovery.
       // See the Azure documentation for details.
       return new DefaultAzureCredential();
   });

   // ...
   ```

### Prevent Azure cache folders from bloating

In private cloud, Xperience projects using Azure Blob storage cache data from the blob storage on the local file system. This cached data is stored in the **AzureTemp** and **AzureCache** folders (see [Optional application settings](#optional-application-settings-for-azure-storage) for custom path configuration).

When these folders accumulate too much data, the local storage can become full, potentially causing errors in your application.

Xperience by Kentico automatically monitors and cleans the Azure cache folders using a background process. When the total size of the cache folders exceeds a configured threshold, the system deletes cached files starting from the oldest until the folder size is reduced.

The default cleanup threshold is **45 GB**. This means the system only starts removing cached files once the combined size of the AzureTemp and AzureCache folders exceeds 45 GB.

> **Warning:** The default 45 GB threshold may be too high for hosting environments with limited disk space. If your App Service Plan's total storage limit is below 45 GB, the default threshold can never be reached and cache files keep growing until the disk is full.
>
> Adjust the threshold to a value appropriate for your deployment's storage capacity.

#### Configure the cleanup threshold

Configure the cleanup threshold using the `AzureStorageCleanerOptions` class in your application's startup code (`Program.cs`):

```csharp title="Program.cs"
using Kentico.Xperience.AzureStorage;

builder.Services.Configure<AzureStorageCleanerOptions>(options =>
{
    // Sets the threshold to 10 GB (value is in bytes)
    options.Treshold = 10L * 1024L * 1024L * 1024L;
});
```

Set the `Treshold` property to a value in **bytes** that is lower than your hosting environment's available disk space. Leave enough headroom for the application itself and other files on the disk.
