# Set up Azure App Service in the AppHost

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

<Badge text="🧪 Preview" variant="note" size="large" />

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

If you're new to the Azure App Service integration, start with the [Get started with the Azure App Service integration](/integrations/cloud/azure/azure-app-service/azure-app-service-get-started/) guide. For how deployed apps consume the runtime configuration this integration injects, see [Azure App Service runtime configuration](../azure-app-service-connect/).

## Installation

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

```bash title="Terminal"
aspire add Aspire.Hosting.Azure.AppService
```

<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.AppService@*
```

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

```bash title="Terminal"
aspire add Aspire.Hosting.Azure.AppService
```

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

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

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

## Add Azure App Service environment

To deploy compute resources to Azure App Service, first add an App Service environment to your AppHost. The environment represents the hosting infrastructure (App Service Plan) into which Aspire deploys your project and container resources.

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

var appServiceEnv = builder.AddAzureAppServiceEnvironment("app-service-env");

builder.AddProject<Projects.WebApi>("api");

// 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 appServiceEnv =
  await builder.addAzureAppServiceEnvironment('app-service-env');

await builder.addProject('api', '../WebApi/WebApi.csproj');

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

1. When you call `addAzureAppServiceEnvironment` (or `AddAzureAppServiceEnvironment` in C#), Aspire implicitly enables Azure provisioning for the application.

2. All project resources and Dockerfile-backed containers in the AppHost are **automatically targeted** to the App Service environment when it's present — no explicit wiring is required.

3. During local development the projects run locally as usual. When you publish, each eligible resource is deployed as an Azure App Service website within the provisioned environment.
**Caution:** Calling `AddAzureAppServiceEnvironment` (or `addAzureAppServiceEnvironment` in
  TypeScript) implicitly calls `AddAzureProvisioning`, which adds support for
  generating Azure resources dynamically during app startup. The app must
  configure an Azure subscription and location. For more information, see [Local
  provisioning:
  Configuration](/integrations/cloud/azure/local-provisioning/#configuration).
**Note:** Backing services such as databases, caches, and message brokers should use
  their own managed Azure services rather than App Service websites. Only
  web-facing compute resources — project resources and Dockerfile-backed
  containers — are deployed as App Service websites.

When the App Service environment is provisioned in Azure, the following resources are created:

- **App Service Plan** — A Premium P0V3 Linux-based hosting plan.
- **Azure Container Registry** — A Basic SKU registry for storing container images.
- **User-assigned Managed Identity** — For secure access between App Service and the Container Registry.
- **Role Assignments** — ACR Pull role assigned to the managed identity.

## Connect to an existing App Service plan

If you already have an App Service plan in Azure, annotate your environment resource as existing to use it instead of provisioning a new one:

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

var existingAppServicePlanName = builder.AddParameter("existingAppServicePlanName");
var existingResourceGroup = builder.AddParameter("existingResourceGroup");

var appServiceEnv = builder.AddAzureAppServiceEnvironment("app-service-env")
    .AsExisting(existingAppServicePlanName, existingResourceGroup);

builder.AddProject<Projects.WebApi>("api");

// 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 existingAppServicePlanName = await builder.addParameter(
  'existingAppServicePlanName'
);
const existingResourceGroup = await builder.addParameter(
  'existingResourceGroup'
);

const appServiceEnv =
  await builder.addAzureAppServiceEnvironment('app-service-env');
await appServiceEnv.asExisting(
  existingAppServicePlanName,
  existingResourceGroup
);

await builder.addProject('api', '../WebApi/WebApi.csproj');

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

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

## Customize App Service websites

By default, Aspire generates an App Service website for each eligible resource without additional configuration. Use `PublishAsAzureAppServiceWebsite` (C#) or `publishAsAzureAppServiceWebsite` (TypeScript) when you need to customize the generated website — for example to add application settings or tags:

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

builder.AddAzureAppServiceEnvironment("app-service-env");

builder.AddProject<Projects.WebApi>("api")
    .PublishAsAzureAppServiceWebsite((infra, website) =>
    {
        website.AppSettings.Add("ASPNETCORE_ENVIRONMENT", new AppServiceConfigurationSetting
        {
            Name = "ASPNETCORE_ENVIRONMENT",
            Value = "Production"
        });

        website.Tags.Add("Environment", "Production");
        website.Tags.Add("Team", "Engineering");
    });

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

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

const builder = await createBuilder();

await builder.addAzureAppServiceEnvironment('app-service-env');

const api = await builder.addProject('api', '../WebApi/WebApi.csproj');
await api.publishAsAzureAppServiceWebsite({
  configure: async (infra, website) => {
    // Customize infrastructure here using Azure Provisioning APIs
  },
});

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

The preceding code:

- Adds an App Service environment.
- Chains a call to `PublishAsAzureAppServiceWebsite` (or `publishAsAzureAppServiceWebsite`) with a customization callback.
- In C#, adds an application setting for `ASPNETCORE_ENVIRONMENT` and metadata tags.
**Note:** When App Service deployment configures a managed identity for a resource,
  Aspire automatically sets the `AZURE_TOKEN_CREDENTIALS` environment variable
  to `ManagedIdentityCredential`. This ensures that `DefaultAzureCredential`
  uses only `ManagedIdentityCredential` for authentication, following [Azure SDK
  best
  practices](https://learn.microsoft.com/dotnet/azure/sdk/authentication/best-practices?tabs=aspdotnet#use-deterministic-credentials-in-production-environments).
  If you need a different credential type, remove this app setting by
  customizing the generated website with `PublishAsAzureAppServiceWebsite`.

## Deployment slots

[Deployment slots](https://learn.microsoft.com/azure/app-service/deploy-staging-slots) let you deploy your app to a staging environment for testing before swapping it into production. The `WithDeploymentSlot` extension method (or `withDeploymentSlot` in TypeScript) configures a deployment slot for the App Service environment:

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

builder.AddAzureAppServiceEnvironment("appservice")
    .WithDeploymentSlot("staging");

var apiService = builder.AddProject<Projects.ApiService>("apiservice")
    .WithHttpHealthCheck("/health")
    .WithExternalHttpEndpoints();

builder.AddProject<Projects.Web>("webfrontend")
    .WithExternalHttpEndpoints()
    .WithHttpHealthCheck("/health")
    .WithReference(apiService)
    .WaitFor(apiService);

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

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

const builder = await createBuilder();

await (
  await builder.addAzureAppServiceEnvironment('appservice')
).withDeploymentSlot('staging');

const apiService = await builder.addProject(
  'apiservice',
  '../ApiService/ApiService.csproj'
);

await builder
  .addProject('webfrontend', '../Web/Web.csproj')
  .withReference(apiService)
  .waitFor(apiService);

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

The preceding code configures all App Service websites to be deployed to a `staging` slot.

### Deployment slot behavior

When you deploy to a slot, the deployment behavior depends on whether the production App Service already exists:

- **New App Service**: If the production App Service doesn't exist at the time of deployment, Aspire deploys to both the production App Service and the specified deployment slot.
- **Existing App Service**: If the production App Service already exists, Aspire deploys only to the specified deployment slot.

### Using parameters for deployment slots

Specify the deployment slot name as a parameter so that it can be provided at deployment time:

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

var slotName = builder.AddParameter("deploymentSlot");

builder.AddAzureAppServiceEnvironment("appservice")
    .WithDeploymentSlot(slotName);

// Add your projects and other resources...

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

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

const builder = await createBuilder();

const slotName = await builder.addParameter('deploymentSlot');

await (
  await builder.addAzureAppServiceEnvironment('appservice')
).withDeploymentSlot(slotName);

// Add your projects and other resources...

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

With this configuration, provide a value for the `deploymentSlot` parameter when running [`aspire deploy`](/reference/cli/commands/aspire-deploy/).

### Applying customizations to slots
**Caution:** Customizations applied to the production App Service are not automatically
  applied to deployment slots. You must explicitly apply customizations to the
  slot when needed.

When you customize App Service resources using `PublishAsAzureAppServiceWebsite` (or `publishAsAzureAppServiceWebsite`) or `ConfigureInfrastructure`, those customizations apply to the production slot by default. Apply them separately to each slot when needed using the `configureSlot` option:

```csharp title="C# — AppHost.cs"
builder.AddProject<Projects.WebApi>("api")
    .PublishAsAzureAppServiceWebsite((infra, website) =>
    {
        website.Tags.Add("Slot", "production");
    });
```

```typescript title="apphost.mts"
const api = await builder.addProject('api', '../WebApi/WebApi.csproj');
await api.publishAsAzureAppServiceWebsite({
  configure: async (infra, website) => {
    // Production website customizations
  },
  configureSlot: async (infra, slot) => {
    // Deployment slot customizations
  },
});
```

## Customize provisioning infrastructure

All Aspire Azure resources expose a `ConfigureInfrastructure` API (or `configureInfrastructure` in TypeScript) that lets you customize the generated Bicep through the [Azure.Provisioning](https://learn.microsoft.com/dotnet/api/azure.provisioning) APIs. For example, you can change the App Service Plan SKU:

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

var appServiceEnv = builder.AddAzureAppServiceEnvironment("app-service-env")
    .ConfigureInfrastructure(infra =>
    {
        var resources = infra.GetProvisionableResources();
        var plan = resources.OfType<AppServicePlan>().Single();

        plan.Sku = new AppServiceSkuDescription
        {
            Name = "P1V3",
            Tier = "Premium"
        };

        plan.Tags.Add("Environment", "Production");
        plan.Tags.Add("CostCenter", "Engineering");
    });

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

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

const builder = await createBuilder();

await (
  await builder.addAzureAppServiceEnvironment('app-service-env')
).configureInfrastructure(async (infra) => {
  // Customize Azure Provisioning resources here
});

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

The preceding code:

- Chains a call to the `ConfigureInfrastructure` API.
- Retrieves the provisionable resources and locates the single `AppServicePlan`.
- Changes the SKU to a P1V3 Premium tier.
- Adds tags for metadata and cost management.

For more information, see `Azure.Provisioning.AppService` and [Azure.Provisioning customization](/integrations/cloud/azure/customize-resources/#azureprovisioning-customization).

## 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 — the provisioning APIs generate it for you. When you publish your app, the generated Bicep is output alongside the manifest file.

When you add an Azure App Service environment, the following key resources are provisioned:

- **App Service Plan** — A Premium P0V3 Linux-based hosting plan.
- **Azure Container Registry** — A Basic SKU registry for storing container images.
- **User-assigned Managed Identity** — For secure access between App Service and Container Registry.
- **Role Assignments** — ACR Pull role assigned to the managed identity.

The generated Bicep is a starting point and is influenced by changes to the provisioning infrastructure in your AppHost. Customize the Bicep through the C# or TypeScript provisioning APIs — direct edits to generated Bicep files are overwritten on the next publish.

## See also

- [Azure App Service runtime configuration](../azure-app-service-connect/)
- [Local Azure provisioning](/integrations/cloud/azure/local-provisioning/)
- [Use existing Azure resources](/integrations/cloud/azure/overview/#use-existing-azure-resources)
- [Azure.Provisioning customization](/integrations/cloud/azure/customize-resources/)