Skip to content
DocsTry Aspire
DocsTry

Set up Azure App Service in the AppHost

Azure App Service logo 🧪 Preview

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

If you’re new to the Azure App Service integration, start with the Get started with the Azure App Service integration guide. For how deployed apps consume the runtime configuration this integration injects, see Azure App Service runtime configuration.

To start building an Aspire app that targets Azure App Service, install the 📦 Aspire.Hosting.Azure.AppService NuGet package:

Terminal
aspire add Aspire.Hosting.Azure.AppService

Learn more about aspire add in the command reference.

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

aspire.config.json
{
"packages": {
"Aspire.Hosting.Azure.AppService": "13.5.3"
}
}

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.

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.

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.

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:

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.

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:

apphost.mts
import {
function createBuilder(): IDistributedApplicationBuilder

Creates a new distributed application builder

createBuilder
} from './.aspire/modules/aspire.mjs';
const
const builder: IDistributedApplicationBuilder
builder
= await
function createBuilder(): IDistributedApplicationBuilder

Creates a new distributed application builder

createBuilder
();
await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addAzureAppServiceEnvironment(name: string): AzureAppServiceEnvironmentResource

Adds a azure app service environment resource to the distributed application builder.

addAzureAppServiceEnvironment
('app-service-env');
const
const api: ProjectResource
api
= await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addProject(name: string, projectPath: string, options?: {
launchProfileOrOptions?: ProjectResourceOptions;
}): ProjectResource (+1 overload)

Adds a .NET project resource

addProject
('api', '../WebApi/WebApi.csproj');
await
const api: ProjectResource
api
.
ProjectResource.publishAsAzureAppServiceWebsite(options?: {
configure?: ((arg1: AzureResourceInfrastructure, arg2: WebSite) => Promise<void>) | undefined;
configureSlot?: ((arg1: AzureResourceInfrastructure, arg2: WebSiteSlot) => Promise<void>) | undefined;
} | undefined): ProjectResource (+1 overload)

Publishes the specified compute resource as an Azure App Service or Azure App Service Slot.

publishAsAzureAppServiceWebsite
({
configure?: ((arg1: AzureResourceInfrastructure, arg2: WebSite) => Promise<void>) | undefined
configure
: async (
infra: AzureResourceInfrastructure
infra
,
website: WebSite
website
) => {
// Customize infrastructure here using Azure Provisioning APIs
},
});
await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.build(): DistributedApplication

Builds the distributed application

build
().
DistributedApplication.run(cancellationToken?: cancellationToken): void

Runs the distributed application

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.

Deployment 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:

apphost.mts
import {
function createBuilder(): IDistributedApplicationBuilder

Creates a new distributed application builder

createBuilder
} from './.aspire/modules/aspire.mjs';
const
const builder: IDistributedApplicationBuilder
builder
= await
function createBuilder(): IDistributedApplicationBuilder

Creates a new distributed application builder

createBuilder
();
await (
await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addAzureAppServiceEnvironment(name: string): AzureAppServiceEnvironmentResource

Adds a azure app service environment resource to the distributed application builder.

addAzureAppServiceEnvironment
('appservice')
).
AzureAppServiceEnvironmentResource.withDeploymentSlot(deploymentSlot: string | ParameterResource): AzureAppServiceEnvironmentResource

Configures the deployment slot for all Azure App Services in the environment

withDeploymentSlot
('staging');
const
const apiService: ProjectResource
apiService
= await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addProject(name: string, projectPath: string, options?: {
launchProfileOrOptions?: ProjectResourceOptions;
}): ProjectResource (+1 overload)

Adds a .NET project resource

addProject
(
'apiservice',
'../ApiService/ApiService.csproj'
);
await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addProject(name: string, projectPath: string, options?: {
launchProfileOrOptions?: ProjectResourceOptions;
}): ProjectResource (+1 overload)

Adds a .NET project resource

addProject
('webfrontend', '../Web/Web.csproj')
.
ProjectResource.withReference(source: EndpointReference | string | uri, options?: {
connectionName?: string;
optional?: boolean;
name?: string;
} | undefined): ProjectResource (+1 overload)

Adds a reference to another resource

withReference
(
const apiService: ProjectResource
apiService
)
.
ProjectResource.waitFor(dependency: IResource | IResourceWithConnectionString, waitBehavior?: WaitBehavior): ProjectResource

Waits for another resource to be ready

waitFor
(
const apiService: ProjectResource
apiService
);
await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.build(): DistributedApplication

Builds the distributed application

build
().
DistributedApplication.run(cancellationToken?: cancellationToken): void

Runs the distributed application

run
();

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

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.

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

apphost.mts
import {
function createBuilder(): IDistributedApplicationBuilder

Creates a new distributed application builder

createBuilder
} from './.aspire/modules/aspire.mjs';
const
const builder: IDistributedApplicationBuilder
builder
= await
function createBuilder(): IDistributedApplicationBuilder

Creates a new distributed application builder

createBuilder
();
const
const slotName: ParameterResource
slotName
= await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addParameter(name: string, options?: {
value?: string;
publishValueAsDefault?: boolean;
secret?: boolean;
}): ParameterResource (+1 overload)

Adds a parameter resource

addParameter
('deploymentSlot');
await (
await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addAzureAppServiceEnvironment(name: string): AzureAppServiceEnvironmentResource

Adds a azure app service environment resource to the distributed application builder.

addAzureAppServiceEnvironment
('appservice')
).
AzureAppServiceEnvironmentResource.withDeploymentSlot(deploymentSlot: string | ParameterResource): AzureAppServiceEnvironmentResource

Configures the deployment slot for all Azure App Services in the environment

withDeploymentSlot
(
const slotName: ParameterResource
slotName
);
// Add your projects and other resources...
await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.build(): DistributedApplication

Builds the distributed application

build
().
DistributedApplication.run(cancellationToken?: cancellationToken): void

Runs the distributed application

run
();

With this configuration, provide a value for the deploymentSlot parameter when running aspire deploy.

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:

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
},
});

To configure regional virtual network integration for the websites in an App Service environment, add the 📦 Aspire.Hosting.Azure.Network integration and delegate a subnet to the environment with WithDelegatedSubnet (or withDelegatedSubnet in TypeScript):

apphost.mts
import { createBuilder } from './.aspire/modules/aspire.mjs';
const builder = await createBuilder();
const vnet = await builder.addAzureVirtualNetwork('vnet');
const subnet = await vnet.addSubnet('app-service-subnet', '10.0.0.0/24');
const appServiceEnv = await builder
.addAzureAppServiceEnvironment('app-service-env')
.withDelegatedSubnet(subnet);
await builder.addProject('api', '../WebApi/WebApi.csproj');
await builder.build().run();

WithDelegatedSubnet delegates the subnet to Microsoft.Web/serverFarms and configures every generated website, deployment slot, and the default Aspire Dashboard to use it for regional virtual network integration. The subnet must meet the Azure App Service regional virtual network integration requirements.

For more information on configuring virtual networks and subnets, see Azure Virtual Network.

All Aspire Azure resources expose a ConfigureInfrastructure API (or configureInfrastructure in TypeScript) that lets you customize the generated Bicep through the Azure.Provisioning APIs. For example, you can change the App Service Plan SKU:

apphost.mts
import {
function createBuilder(): IDistributedApplicationBuilder

Creates a new distributed application builder

createBuilder
} from './.aspire/modules/aspire.mjs';
const
const builder: IDistributedApplicationBuilder
builder
= await
function createBuilder(): IDistributedApplicationBuilder

Creates a new distributed application builder

createBuilder
();
await (
await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addAzureAppServiceEnvironment(name: string): AzureAppServiceEnvironmentResource

Adds a azure app service environment resource to the distributed application builder.

addAzureAppServiceEnvironment
('app-service-env')
).
AzureProvisioningResource.configureInfrastructure(configure: (obj: AzureResourceInfrastructure) => Promise<void>): AzureProvisioningResource

Configures the Azure provisioning infrastructure callback

configureInfrastructure
(async (
infra: AzureResourceInfrastructure
infra
) => {
// Customize Azure Provisioning resources here
});
await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.build(): DistributedApplication

Builds the distributed application

build
().
DistributedApplication.run(cancellationToken?: cancellationToken): void

Runs the distributed application

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.

If you’re new to Bicep, 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.