---
title: Set up Azure App Configuration in the AppHost
description: Learn how to use the Aspire Azure App Configuration Hosting integration to orchestrate and configure an App Configuration store in an Aspire solution.
---

<Image
  src={appConfigIcon}
  alt="Azure App Configuration logo"
  width={100}
  height={100}
  class:list={'float-inline-left icon'}
  data-zoom-off
/>

This article is the reference for the Aspire Azure App Configuration Hosting integration. It enumerates the AppHost APIs — with examples for both `AppHost.cs` and `apphost.mts` — that you use to model an Azure App Configuration store in your [`AppHost`](/get-started/app-host/) project.

If you're new to the Azure App Configuration integration, start with the [Get started with Azure App Configuration integrations](/integrations/cloud/azure/azure-app-configuration/azure-app-configuration-get-started/) guide. For how consuming apps read the connection information this page exposes, see [Connect to Azure App Configuration](../azure-app-configuration-connect/).

## Installation

To start building an Aspire app that uses Azure App Configuration, install the [📦 Aspire.Hosting.Azure.AppConfiguration](https://www.nuget.org/packages/Aspire.Hosting.Azure.AppConfiguration) NuGet package:

```bash title="Terminal"
aspire add azure-app-configuration
```

<LearnMore>
  Learn more about [`aspire add`](/reference/cli/commands/aspire-add/) in the command reference.
</LearnMore>

Or, choose a manual installation approach:

```csharp title="C# — AppHost.cs"
#:package Aspire.Hosting.Azure.AppConfiguration@*
```

```xml title="XML — AppHost.csproj"
<PackageReference Include="Aspire.Hosting.Azure.AppConfiguration" Version="*" />
```

```bash title="Terminal"
aspire add azure-app-configuration
```

<LearnMore>
  Learn more about [`aspire add`](/reference/cli/commands/aspire-add/) in the command reference.
</LearnMore>

This updates your `aspire.config.json` with the Azure App Configuration hosting integration package:

```json title="aspire.config.json" ins={3}
{
  "packages": {
    "Aspire.Hosting.Azure.AppConfiguration": "13.3.0"
  }
}
```

## Add Azure App Configuration resource

Once you've installed the hosting integration in your AppHost project, you can add an Azure App Configuration resource as shown in the following examples:

```csharp title="C# — AppHost.cs"
var builder = DistributedApplication.CreateBuilder(args);

var appConfig = builder.AddAzureAppConfiguration("config");

builder.AddProject<Projects.WebApplication>("web")
    .WithReference(appConfig);

// After adding all resources, run the app...

builder.Build().Run();
```

```typescript title="apphost.mts"
import { createBuilder } from './.aspire/modules/aspire.mjs';

const builder = await createBuilder();

const appConfig = await builder.addAzureAppConfiguration("config");

await builder.addProject("web", "../WebApplication/WebApplication.csproj")
    .withReference(appConfig);

// After adding all resources, run the app...

await builder.build().run();
```
**Caution:** When you call `AddAzureAppConfiguration` (or `addAzureAppConfiguration`), it implicitly calls
  `AddAzureProvisioning`—which adds support for generating Azure resources
  dynamically during app startup. The app must configure the appropriate
  subscription and location. For more information, see [Local provisioning:
  Configuration](/integrations/cloud/azure/local-provisioning/#configuration).
**Note:** When you reference an Azure App Configuration resource from the AppHost, Aspire makes the store endpoint available to the consuming project. For a complete list of these properties and per-language connection examples, see [Connect to Azure App Configuration](../azure-app-configuration-connect/).

## Provisioning-generated Bicep

If you're new to [Bicep](https://learn.microsoft.com/azure/azure-resource-manager/bicep/overview), it's a domain-specific language for defining Azure resources. With Aspire, you don't need to write Bicep by hand — instead the provisioning APIs generate Bicep for you. When you publish your app, the generated Bicep is output alongside the manifest file. When you add an Azure App Configuration resource, the following Bicep is generated:

```bicep title="Generated Bicep — config.bicep"
@description('The location for the resource(s) to be deployed.')
param location string = resourceGroup().location

resource config 'Microsoft.AppConfiguration/configurationStores@2024-06-01' = {
  name: take('config-${uniqueString(resourceGroup().id)}', 50)
  location: location
  properties: {
    disableLocalAuth: true
  }
  sku: {
    name: 'standard'
  }
  tags: {
    'aspire-resource-name': 'config'
  }
}

output appConfigEndpoint string = config.properties.endpoint

output name string = config.name
```

The preceding Bicep is a module that provisions an Azure App Configuration store. Additionally, role assignments are created for the Azure resource in a separate module:

```bicep title="Generated Bicep — config-roles.bicep"
@description('The location for the resource(s) to be deployed.')
param location string = resourceGroup().location

param config_outputs_name string

param principalType string

param principalId string

resource config 'Microsoft.AppConfiguration/configurationStores@2024-06-01' existing = {
  name: config_outputs_name
}

resource config_AppConfigurationDataOwner 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
  name: guid(config.id, principalId, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5ae67dd6-50cb-40e7-96ff-dc2bfa4b606b'))
  properties: {
    principalId: principalId
    roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5ae67dd6-50cb-40e7-96ff-dc2bfa4b606b')
    principalType: principalType
  }
  scope: config
}
```

The generated Bicep is a starting point and is influenced by changes to the provisioning infrastructure in C#. Customizations to the Bicep file directly will be overwritten, so make changes through the C# provisioning APIs to ensure they're reflected in the generated files.

## Customize provisioning infrastructure

All Aspire Azure resources are subclasses of the `AzureProvisioningResource` type. This type enables the customization of the generated Bicep by providing a fluent API to configure the Azure resources — using the `ConfigureInfrastructure` API (or `configureInfrastructure` in TypeScript). For example, you can configure the SKU, enable purge protection, add tags, and more:

```csharp title="C# — AppHost.cs"
var builder = DistributedApplication.CreateBuilder(args);

builder.AddAzureAppConfiguration("config")
    .ConfigureInfrastructure(infra =>
    {
        var appConfigStore = infra.GetProvisionableResources()
                                  .OfType<AppConfigurationStore>()
                                  .Single();

        appConfigStore.SkuName = "Free";
        appConfigStore.EnablePurgeProtection = true;
        appConfigStore.Tags.Add("ExampleKey", "Example value");
    });
```

```typescript title="apphost.mts"
import { createBuilder } from './.aspire/modules/aspire.mjs';

const builder = await createBuilder();

await builder.addAzureAppConfiguration("config")
    .configureInfrastructure(async infra => {
        const resources = await infra.getProvisionableResources();
        const store = resources.find(r => r.$type === 'AppConfigurationStore');
        if (store) {
            store.skuName = "Free";
            store.enablePurgeProtection = true;
            store.tags = { ...store.tags, ExampleKey: "Example value" };
        }
    });
```

The preceding code:

- Chains a call to the `ConfigureInfrastructure` API:
  - The `infra` parameter is an instance of the `AzureResourceInfrastructure` type.
  - The provisionable resources are retrieved by calling the `GetProvisionableResources` method.
  - The single `AppConfigurationStore` is retrieved.
  - The `AppConfigurationStore.SkuName` is assigned to `Free`.
  - A tag is added to the App Configuration store with a key of `ExampleKey` and a value of `Example value`.

There are many more configuration options available to customize the Azure App Configuration resource. For more information, see [Azure.Provisioning customization](/integrations/cloud/azure/customize-resources/#azureprovisioning-customization).

## Add Azure App Configuration emulator resource

Microsoft provides the Azure App Configuration emulator for developers who want a local, lightweight implementation of the Azure App Configuration service to code and test against. In Aspire, you can use this emulator by calling the `RunAsEmulator` method (or `runAsEmulator`) when you add your resource:

```csharp title="C# — AppHost.cs"
var builder = DistributedApplication.CreateBuilder(args);

var appConfig = builder.AddAzureAppConfiguration("config")
    .RunAsEmulator();

// After adding all resources, run the app...

builder.Build().Run();
```

```typescript title="apphost.mts"
import { createBuilder } from './.aspire/modules/aspire.mjs';

const builder = await createBuilder();

const appConfig = await builder.addAzureAppConfiguration("config")
    .runAsEmulator();

// After adding all resources, run the app...

await builder.build().run();
```

The Azure App Configuration emulator isn't installed on your local computer. Instead, it's accessible to Aspire as a container. The `RunAsEmulator` method creates and starts the container when the AppHost starts using the `azure-app-configuration/app-configuration-emulator` image.

### Configure Azure App Configuration emulator container

There are various configurations available to container resources. For example, you can configure the container's port, lifetime, and data persistence.

#### Configure Azure App Configuration emulator host port

By default, Aspire assigns a random host port for the emulator container. If you want to use a specific port, chain calls on the container resource builder provided by the `RunAsEmulator` method as shown in the following example:

```csharp title="C# — AppHost.cs"
var builder = DistributedApplication.CreateBuilder(args);

var appConfig = builder.AddAzureAppConfiguration("config")
    .RunAsEmulator(emulator =>
    {
        emulator.WithHostPort(28000);
    });

// After adding all resources, run the app...
```

```typescript title="apphost.mts"
import { createBuilder } from './.aspire/modules/aspire.mjs';

const builder = await createBuilder();

const appConfig = await builder.addAzureAppConfiguration("config")
    .runAsEmulator({
        configureEmulator: async emulator => {
            await emulator.withHostPort({ port: 28000 });
        }
    });

// After adding all resources, run the app...
```

The preceding code configures the emulator container's endpoint to listen on port `28000`.

#### Configure Azure App Configuration emulator with persistent lifetime

To configure the emulator container with a persistent lifetime, call the `WithLifetime` method (or `withLifetime`) on the emulator container resource and pass `ContainerLifetime.Persistent`:

```csharp title="C# — AppHost.cs"
var builder = DistributedApplication.CreateBuilder(args);

var appConfig = builder.AddAzureAppConfiguration("config")
    .RunAsEmulator(emulator =>
    {
        emulator.WithLifetime(ContainerLifetime.Persistent);
    });

// After adding all resources, run the app...
```

```typescript title="apphost.mts"
import { createBuilder, ContainerLifetime } from './.aspire/modules/aspire.mjs';

const builder = await createBuilder();

const appConfig = await builder.addAzureAppConfiguration("config")
    .runAsEmulator({
        configureEmulator: async emulator => {
            await emulator.withLifetime(ContainerLifetime.Persistent);
        }
    });

// After adding all resources, run the app...
```

#### Configure Azure App Configuration emulator with data volume

By default, the Azure App Configuration emulator doesn't persist data between container restarts. To enable persistent storage using a Docker volume, call the `WithDataVolume` method (or `withDataVolume`) on the emulator resource:

```csharp title="C# — AppHost.cs"
var builder = DistributedApplication.CreateBuilder(args);

var appConfig = builder.AddAzureAppConfiguration("config")
    .RunAsEmulator(emulator =>
    {
        emulator.WithDataVolume();
    });

// After adding all resources, run the app...
```

```typescript title="apphost.mts"
import { createBuilder } from './.aspire/modules/aspire.mjs';

const builder = await createBuilder();

const appConfig = await builder.addAzureAppConfiguration("config")
    .runAsEmulator({
        configureEmulator: async emulator => {
            await emulator.withDataVolume();
        }
    });

// After adding all resources, run the app...
```

The data volume is used to persist the emulator data outside the lifecycle of its container, ensuring configuration values survive container restarts. The data volume is mounted at the `/data` path in the emulator container. For more information on data volumes and details on why they're preferred over [bind mounts](#configure-azure-app-configuration-emulator-with-data-bind-mount), see [Docker docs: Volumes](https://docs.docker.com/engine/storage/volumes).

#### Configure Azure App Configuration emulator with data bind mount

To persist emulator data to a specific directory on your host machine, call the `WithDataBindMount` method (or `withDataBindMount`). This is useful when you want direct access to the data files on your host system:

```csharp title="C# — AppHost.cs"
var builder = DistributedApplication.CreateBuilder(args);

var appConfig = builder.AddAzureAppConfiguration("config")
    .RunAsEmulator(emulator =>
    {
        emulator.WithDataBindMount("../Emulator/Data");
    });

// After adding all resources, run the app...
```

```typescript title="apphost.mts"
import { createBuilder } from './.aspire/modules/aspire.mjs';

const builder = await createBuilder();

const appConfig = await builder.addAzureAppConfiguration("config")
    .runAsEmulator({
        configureEmulator: async emulator => {
            await emulator.withDataBindMount({ path: "../Emulator/Data" });
        }
    });

// After adding all resources, run the app...
```

:::note
Data [bind mounts](https://docs.docker.com/engine/storage/bind-mounts/) have limited functionality compared to [volumes](https://docs.docker.com/engine/storage/volumes/), which offer better performance, portability, and security, making them more suitable for production environments. However, bind mounts allow direct access and modification of files on the host system, ideal for development and testing where real-time changes are needed.
:::

Data bind mounts rely on the host machine's filesystem to persist the emulator data across container restarts. The data bind mount is mounted at the `../Emulator/Data` path on the host machine relative to the AppHost directory in the emulator container. For more information on data bind mounts, see [Docker docs: Bind mounts](https://docs.docker.com/engine/storage/bind-mounts).

## Use existing Azure App Configuration resource

You might have an existing Azure App Configuration store that you want to connect to. Call the `AsExisting` method (or `asExisting`) with the config store name and resource group parameters to connect to an existing store:

```csharp title="C# — AppHost.cs"
var builder = DistributedApplication.CreateBuilder(args);

var configName = builder.AddParameter("configName");
var configResourceGroupName = builder.AddParameter("configResourceGroupName");

var appConfig = builder.AddAzureAppConfiguration("config")
    .AsExisting(configName, configResourceGroupName);

// After adding all resources, run the app...

builder.Build().Run();
```

```typescript title="apphost.mts"
import { createBuilder } from './.aspire/modules/aspire.mjs';

const builder = await createBuilder();

const configName = await builder.addParameter("configName");
const configResourceGroupName = await builder.addParameter("configResourceGroupName");

const appConfig = await builder.addAzureAppConfiguration("config")
    .asExisting(configName, { resourceGroup: configResourceGroupName });

// After adding all resources, run the app...

await builder.build().run();
```

For more information, see [Use existing Azure resources](/integrations/cloud/azure/overview/#use-existing-azure-resources).

## Connect to existing Azure App Configuration store

An alternative approach to using the `AsExisting` API enables the addition of a connection string instead, where the AppHost uses configuration to resolve the connection information. To add a connection to an existing Azure App Configuration store, call the `AddConnectionString` method:

```csharp title="C# — AppHost.cs"
var builder = DistributedApplication.CreateBuilder(args);

var config = builder.AddConnectionString("config");

builder.AddProject<Projects.WebApplication>("web")
    .WithReference(config);

// After adding all resources, run the app...

builder.Build().Run();
```

```typescript title="apphost.mts"
import { createBuilder } from './.aspire/modules/aspire.mjs';

const builder = await createBuilder();

const config = await builder.addConnectionString("config");

await builder.addProject("web", "../WebApplication/WebApplication.csproj")
    .withReference(config);

// After adding all resources, run the app...

await builder.build().run();
```

:::note
Connection strings are used to represent a wide range of connection information, including database connections, message brokers, endpoint URIs, and other services. In Aspire nomenclature, the term "connection string" is used to represent any kind of connection information.
:::

The connection string is configured in the AppHost's configuration, typically under [User Secrets](https://learn.microsoft.com/aspnet/core/security/app-secrets), under the `ConnectionStrings` section:

```json title="JSON — appsettings.json"
{
  "ConnectionStrings": {
    "config": "https://{store_name}.azconfig.io"
  }
}
```

## Role-based access control

By default, Aspire provisions the `AppConfigurationDataOwner` role so your app can read and write configuration values. You can customize the roles assigned using the `WithRoleAssignments` method (or `withRoleAssignments`) to grant least-privilege access. For example, to grant read-only access:

```csharp title="C# — AppHost.cs"
var builder = DistributedApplication.CreateBuilder(args);

var appConfig = builder.AddAzureAppConfiguration("config");

builder.AddProject<Projects.WebApplication>("web")
    .WithReference(appConfig)
    .WithRoleAssignments(appConfig, AzureAppConfigurationRole.AppConfigurationDataReader);

// After adding all resources, run the app...

builder.Build().Run();
```

```typescript title="apphost.mts"
import { createBuilder, AzureAppConfigurationRole } from './.aspire/modules/aspire.mjs';

const builder = await createBuilder();

const appConfig = await builder.addAzureAppConfiguration("config");

await appConfig.withRoleAssignments(appConfig, [
    AzureAppConfigurationRole.AppConfigurationDataReader
]);

// After adding all resources, run the app...

await builder.build().run();
```

The available roles are defined in the `AzureAppConfigurationRole` enum:

| Role | Description |
| ---- | ----------- |
| `AppConfigurationDataOwner` | Full access to App Configuration data, including read, write, and delete operations |
| `AppConfigurationDataReader` | Read-only access to App Configuration data |

## Connection properties

For the full reference of Azure App Configuration connection properties — and how consuming apps in C#, TypeScript, Python, and Go read them — see [Connect to Azure App Configuration](../azure-app-configuration-connect/).

## Hosting integration health checks

The Azure App Configuration hosting integration doesn't currently register a hosting-level health check. Client health checks are configured through the [C# client integration](../azure-app-configuration-connect/#client-integration-health-checks).