Local Azure provisioning
This article describes how to enable local Azure provisioning in your Aspire AppHost project. Local Azure provisioning lets Aspire automatically create and configure Azure resources in your Azure subscription during local development â no manual portal or CLI setup required.
How it works
Section titled âHow it worksâWhen you add an Azure resource using methods like AddAzureStorageaddAzureStorage or AddAzureServiceBusaddAzureServiceBus, Aspire:
- Detects that the resource doesnât exist locally
- Generates Bicep infrastructure-as-code
- Uses the configured Azure credential and Azure APIs to deploy resources
- Configures connection information automatically
- Injects configuration into your application
Prerequisites
Section titled âPrerequisitesâBefore using local provisioning, ensure you have:
- Azure subscription: An active Azure subscription
- Azure credentials: A supported local credential source such as Azure CLI (
az login), Visual Studio, Visual Studio Code, or Azure Developer CLI - Appropriate permissions: Contributor access to create resources
- Aspire 9.0+: Local provisioning requires Aspire 9.0 or later
Configuration
Section titled âConfigurationâLocal provisioning requires configuring your Azure subscription and location. You can do this in multiple ways:
User secrets
Section titled âUser secretsâThe recommended approach for development is using the Aspire CLI:
aspire secret set "Azure:SubscriptionId" "your-subscription-id"aspire secret set "Azure:Location" "eastus"appsettings.json
Section titled âappsettings.jsonâAlternatively, configure in appsettings.Development.json:
{ "Azure": { "SubscriptionId": "your-subscription-id", "Location": "eastus" }}Environment variables
Section titled âEnvironment variablesâYou can also use environment variables:
export Azure__SubscriptionId="your-subscription-id"export Azure__Location="eastus"$env:Azure__SubscriptionId = "your-subscription-id"$env:Azure__Location = "eastus"Configuration options
Section titled âConfiguration optionsâThe following configuration options are available:
| Setting | Description | Default |
|---|---|---|
Azure:SubscriptionId | Your Azure subscription ID | (required) |
Azure:Location | Azure region for resources | (required) |
Azure:TenantId | Azure tenant to use when selecting subscriptions and credentials | Current credential tenant |
Azure:ResourceGroup | Specific resource group to create or reuse | Auto-generated |
Azure:ResourceGroupPrefix | Prefix used when Aspire generates a resource group name | rg-aspire |
Azure:CredentialSource | Authentication method for local provisioning | Default |
Azure:AllowResourceGroupCreation | Allow creating resource groups | true |
Azure:CredentialProcessTimeoutSeconds | Timeout in seconds for credential subprocess operations (must be between 5 and 600) | Azure SDK default |
Resource group management
Section titled âResource group managementâBy default, Aspire creates a resource group for your provisioned resources named rg-aspire-{apphost-name}-{random-suffix}. If you set Azure:ResourceGroupPrefix, Aspire uses that prefix instead of rg-aspire.
Use an existing resource group
Section titled âUse an existing resource groupâTo use an existing resource group:
{ "Azure": { "SubscriptionId": "your-subscription-id", "Location": "eastus", "ResourceGroup": "my-existing-rg" }}Disable resource group creation
Section titled âDisable resource group creationâTo prevent Aspire from creating resource groups:
{ "Azure": { "SubscriptionId": "your-subscription-id", "Location": "eastus", "AllowResourceGroupCreation": false, "ResourceGroup": "my-existing-rg" }}Add Azure resources to your AppHost
Section titled âAdd Azure resources to your AppHostâAdd Azure resources to your AppHost using the relevant Add* APIs, then reference them from your consuming projects:
import { createBuilder } from './.aspire/modules/aspire.mjs';
const builder = await createBuilder();
const storage = await builder.addAzureStorage("storage");const blobs = await storage.addBlobs("blobs");
await builder.addNodeApp("webapp", "./webapp", "index.js") .withReference(blobs);
// After adding all resources, run the app...var builder = DistributedApplication.CreateBuilder(args);
var storage = builder.AddAzureStorage("storage");var blobs = storage.AddBlobs("blobs");
builder.AddProject<Projects.WebApp>("webapp") .WithReference(blobs);
// After adding all resources, run the app...Once your AppHost is configured, run the application and Aspire automatically provisions the referenced Azure resources:
-
Configure your Azure subscription (if not already done)
Terminal window aspire secret set "Azure:SubscriptionId" "your-sub-id"aspire secret set "Azure:Location" "eastus" -
Run your application
Terminal window aspire run -
Automatic provisioning
Aspire detects the Azure resources and provisions them automatically. Youâll see output like:
[Azure Provisioning] Creating resource group: rg-myapp[Azure Provisioning] Deploying storage account: stmyapp[Azure Provisioning] Deployment complete
Authentication
Section titled âAuthenticationâWhen Azure:CredentialSource isnât set, local provisioning uses a development-focused DefaultAzureCredential chain. That default supports local credentials such as Azure CLI, Visual Studio, Visual Studio Code, and Azure Developer CLI, while excluding Azure-hosted credentials such as managed identity and workload identity.
If you want to force a specific local credential, set Azure:CredentialSource to one of the supported values:
| Value | Uses |
|---|---|
Default | Development credential chain for local provisioning |
AzureCli | Azure CLI sign-in (az login) |
AzureDeveloperCli | Azure Developer CLI sign-in (azd auth login) |
VisualStudio | Visual Studio Azure account |
VisualStudioCode | Visual Studio Code Azure account |
AzurePowerShell | Azure PowerShell sign-in |
InteractiveBrowser | Browser-based sign-in prompt |
Credential process timeout
Section titled âCredential process timeoutâMost local credential sources (Azure CLI, Azure PowerShell, Visual Studio, and Azure Developer CLI) acquire tokens by invoking a subprocess. On machines where these tools are slow to respond â for example, due to antivirus scanning or network latency â credential validation can time out before authentication completes.
Use Azure:CredentialProcessTimeoutSeconds to override the credential subprocess timeout. The value must be between 5 and 600 seconds. When unset, the Azure SDKâs default timeout is used.
{ "Azure": { "CredentialProcessTimeoutSeconds": 120 }}This setting applies to the AzureCli, AzurePowerShell, VisualStudio, and AzureDeveloperCli credential sources, and to the development credential chain used when CredentialSource isnât explicitly set. It has no effect on InteractiveBrowser or ManagedIdentity credentials, which donât shell out to a subprocess.
Provisioned resource naming
Section titled âProvisioned resource namingâAspire generates unique resource names following Azure naming conventions:
- Storage accounts:
st{appname}{hash}(lowercase, no hyphens) - Key Vaults:
kv-{appname}-{hash}(hyphens allowed) - Service Bus:
sb-{appname}-{hash} - Cosmos DB:
cosmos-{appname}-{hash}
The hash ensures uniqueness across subscriptions.
Generated infrastructure
Section titled âGenerated infrastructureâWhen you use local provisioning, Aspire generates Bicep files in the ./infra directory of your AppHost project. These files:
- Define all Azure resources
- Include configurations and connections
- Can be customized using
ConfigureInfrastructureconfigureInfrastructure - Are used for both local provisioning and production deployment
Example generated structure:
AppHost/âââ infra/ # Bicep files âââ main.bicep âââ storage.bicep âââ servicebus.bicepProgram.csChange a resourceâs Azure location
Section titled âChange a resourceâs Azure locationâLocally provisioned Azure resources expose a change-location dev-time resource command that lets you move an existing resource to a different Azure region without manually deleting it first.
Some Azure resource types are location-immutable â moving them to a new region requires Aspire to delete the existing live resource and recreate it in the new location. Deleting the resource this way can permanently destroy any data it holds, so Aspire requires an explicit acknowledgement before it deletes a live Azure resource as part of a location change:
-
Dashboard: The change-location dialog shows an Allow deletion and possible permanent data loss checkbox. You must select it before Aspire deletes and recreates the resource.
-
Aspire CLI: Pass
--confirm-deleteto thechange-locationresource command:Aspire CLI aspire resource my-storage change-location --location westus2 --confirm-delete true -
MCP: Set
arguments.confirmDeletetotruewhen invoking thechange-locationcommand.
If the acknowledgement is missing, Aspire fails the command before deleting the resource, persisting any location override, resetting provisioning state, or reprovisioning.
Limitations
Section titled âLimitationsâLocal provisioning has some limitations:
- First-run delays: Initial provisioning takes several minutes
- Subscription limits: Subject to Azure subscription quotas
- Network requirements: Requires internet connectivity
- Cost considerations: Provisioned resources incur Azure charges
Troubleshooting
Section titled âTroubleshootingâAuthentication failures
Section titled âAuthentication failuresâIf you see authentication errors:
az loginaz account set --subscription "your-subscription-id"Insufficient permissions
Section titled âInsufficient permissionsâEnsure your account has Contributor role:
az role assignment list --assignee your-email@domain.comResource naming conflicts
Section titled âResource naming conflictsâIf resource names conflict, delete the existing resources or change your app name:
az group delete --name rg-myappView provisioning logs
Section titled âView provisioning logsâEnable detailed logging:
{ "Logging": { "LogLevel": { "Aspire.Hosting.Azure": "13.6.0" } }}Comparison with manual provisioning
Section titled âComparison with manual provisioningâ| Aspect | Local Provisioning | Manual Provisioning |
|---|---|---|
| Setup time | Automatic | Manual Azure Portal/CLI |
| Configuration | Automatic | Manual connection strings |
| Infrastructure as Code | Auto-generated Bicep | Manual Bicep/ARM |
| Development speed | Fast | Slower |
| Learning curve | Lower | Higher |
| Control | Good (via ConfigureInfrastructure) | Full |
| Cost | Pay for provisioned resources | Pay for provisioned resources |