Set up Azure SQL Database in the AppHost
This article is the reference for the Aspire Azure SQL Database Hosting integration. It enumerates the AppHost APIs — with examples for both AppHost.cs and apphost.mts — that you use to model Azure SQL server and database resources in your AppHost project.
If you’re new to the Azure SQL Database integration, start with the Get started with Azure SQL Database integrations guide. For how consuming apps read the connection information this page exposes, see Connect to Azure SQL Database. For the Azure SQL Database Entity Framework Core client integration, see Azure SQL Database EF Core integration.
Installation
Section titled “Installation”To start building an Aspire app that uses Azure SQL Database, install the 📦 Aspire.Hosting.Azure.Sql NuGet package:
aspire add azure-sqlLearn more about aspire add in the
command reference.
Or, choose a manual installation approach:
#:package Aspire.Hosting.Azure.Sql@*<PackageReference Include="Aspire.Hosting.Azure.Sql" Version="*" />aspire add azure-sqlLearn more about aspire add in the
command reference.
This updates your aspire.config.json with the Azure SQL Database hosting integration package:
{ "packages": { "Aspire.Hosting.Azure.Sql": "13.3.0" }}Add Azure SQL server resource and database
Section titled “Add Azure SQL server resource and database”Once you’ve installed the hosting integration in your AppHost project, you can add an Azure SQL server resource and then add a database resource as shown in the following examples:
var builder = DistributedApplication.CreateBuilder(args);
var sql = builder.AddAzureSqlServer("sql");var db = sql.AddDatabase("database");
var exampleProject = builder.AddProject<Projects.ExampleProject>("apiservice").WithReference(db);
// After adding all resources, run the app...builder.Build().Run();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 sql: AzureSqlServerResource
sql = await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addAzureSqlServer(name: string): AzureSqlServerResource
Adds an Azure SQL Database (server) resource to the application model.
addAzureSqlServer("sql");const const db: AzureSqlDatabaseResource
db = await const sql: AzureSqlServerResource
sql.AzureSqlServerResource.addDatabase(name: string, options?: { databaseName?: string;}): AzureSqlDatabaseResource (+1 overload)
Adds an Azure SQL Database to the application model. The Free Offer option will be used when deploying the resource in Azure
addDatabase("database");
await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addNodeApp(name: string, appDirectory: string, scriptPath: string): NodeAppResource
Adds a node application to the application model. Node should be available on the PATH.
addNodeApp("api", "./api", "index.js") .ExecutableResource.withReference(source: EndpointReference | string | uri, options?: { connectionName?: string; optional?: boolean; name?: string;} | undefined): NodeAppResource (+1 overload)
Adds a reference to another resource
withReference(const db: AzureSqlDatabaseResource
db);
// After adding all resources, run the app...await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.build(): DistributedApplication
Builds the distributed application
build().DistributedApplication.run(cancellationToken?: cancellationToken): void
Runs the distributed application
run();-
The
AddAzureSqlServer(oraddAzureSqlServer) call models an Azure SQL Server that is provisioned in Azure when you publish your app. -
Calling
AddDatabase(oraddDatabase) on the returned resource builder models a named database within that server. TheWithReference(orwithReference) call configures a named connection in the consuming project that matches the database resource name. -
When you call
AddAzureSqlServer, it implicitly callsAddAzureProvisioning— which adds support for generating Azure resources dynamically during app startup. The app must configure the appropriate subscription and location.
Run Azure SQL server resource as a container
Section titled “Run Azure SQL server resource as a container”During local development and testing, you can run an Azure SQL server as a local SQL Server container instead of provisioning an actual Azure resource. Call RunAsContainer (or runAsContainer) to switch to a local container:
var builder = DistributedApplication.CreateBuilder(args);
var sql = builder.AddAzureSqlServer("sql").RunAsContainer();
var db = sql.AddDatabase("database");
var exampleProject = builder.AddProject<Projects.ExampleProject>("apiservice").WithReference(db);
// After adding all resources, run the app...builder.Build().Run();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 sql: AzureSqlServerResource
sql = await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addAzureSqlServer(name: string): AzureSqlServerResource
Adds an Azure SQL Database (server) resource to the application model.
addAzureSqlServer("sql");await const sql: AzureSqlServerResource
sql.AzureSqlServerResource.runAsContainer(configureContainer?: (obj: SqlServerServerResource) => Promise<void>): AzureSqlServerResource
Configures an Azure SQL Database (server) resource to run locally in a container.
runAsContainer();
const const db: AzureSqlDatabaseResource
db = await const sql: AzureSqlServerResource
sql.AzureSqlServerResource.addDatabase(name: string, options?: { databaseName?: string;}): AzureSqlDatabaseResource (+1 overload)
Adds an Azure SQL Database to the application model. The Free Offer option will be used when deploying the resource in Azure
addDatabase("database");
await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addNodeApp(name: string, appDirectory: string, scriptPath: string): NodeAppResource
Adds a node application to the application model. Node should be available on the PATH.
addNodeApp("api", "./api", "index.js") .ExecutableResource.withReference(source: EndpointReference | string | uri, options?: { connectionName?: string; optional?: boolean; name?: string;} | undefined): NodeAppResource (+1 overload)
Adds a reference to another resource
withReference(const db: AzureSqlDatabaseResource
db);
// After adding all resources, run the app...await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.build(): DistributedApplication
Builds the distributed application
build().DistributedApplication.run(cancellationToken?: cancellationToken): void
Runs the distributed application
run();When RunAsContainer is active, Aspire pulls a SQL Server container image and runs it locally. The consuming project receives the same connection environment variables it would receive when deployed to Azure, so your code works without modification between local and cloud environments.
Connect to an existing Azure SQL server
Section titled “Connect to an existing Azure SQL server”You might have an existing Azure SQL Database service that you want to connect to. Chain a call to AsExisting (or asExisting) to annotate that your resource already exists in Azure:
var builder = DistributedApplication.CreateBuilder(args);
var existingName = builder.AddParameter("existingSqlServerName");var existingResourceGroup = builder.AddParameter("existingSqlServerResourceGroup");
var sql = builder.AddAzureSqlServer("sql").AsExisting(existingName, existingResourceGroup).AddDatabase("database");
builder.AddProject<Projects.ExampleProject>("apiservice").WithReference(sql);
// After adding all resources, run the app...builder.Build().Run();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 existingName: ParameterResource
existingName = await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addParameter(name: string, options?: { value?: string; publishValueAsDefault?: boolean; secret?: boolean;}): ParameterResource (+1 overload)
Adds a parameter resource
addParameter("existingSqlServerName");const const existingResourceGroup: ParameterResource
existingResourceGroup = await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addParameter(name: string, options?: { value?: string; publishValueAsDefault?: boolean; secret?: boolean;}): ParameterResource (+1 overload)
Adds a parameter resource
addParameter("existingSqlServerResourceGroup");
const const sql: AzureSqlServerResource
sql = await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addAzureSqlServer(name: string): AzureSqlServerResource
Adds an Azure SQL Database (server) resource to the application model.
addAzureSqlServer("sql");await const sql: AzureSqlServerResource
sql.AzureBicepResource.asExisting(name: string | ParameterResource, resourceGroup?: string | ParameterResource): IAzureResource
Marks the resource as an existing resource in both run and publish modes.
asExisting(const existingName: ParameterResource
existingName, const existingResourceGroup: ParameterResource
existingResourceGroup);const const db: AzureSqlDatabaseResource
db = await const sql: AzureSqlServerResource
sql.AzureSqlServerResource.addDatabase(name: string, options?: { databaseName?: string;}): AzureSqlDatabaseResource (+1 overload)
Adds an Azure SQL Database to the application model. The Free Offer option will be used when deploying the resource in Azure
addDatabase("database");
await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addNodeApp(name: string, appDirectory: string, scriptPath: string): NodeAppResource
Adds a node application to the application model. Node should be available on the PATH.
addNodeApp("api", "./api", "index.js") .ExecutableResource.withReference(source: EndpointReference | string | uri, options?: { connectionName?: string; optional?: boolean; name?: string;} | undefined): NodeAppResource (+1 overload)
Adds a reference to another resource
withReference(const db: AzureSqlDatabaseResource
db);
// After adding all resources, run the app...await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.build(): DistributedApplication
Builds the distributed application
build().DistributedApplication.run(cancellationToken?: cancellationToken): void
Runs the distributed application
run();For more information on treating Azure resources as existing resources, see Use existing Azure resources.
Provisioning-generated Bicep
Section titled “Provisioning-generated Bicep”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 Bicep for you. When you publish your app, the generated Bicep is output alongside the manifest file. When you add an Azure SQL Server resource, the following Bicep is generated:
@description('The location for the resource(s) to be deployed.')param location string = resourceGroup().location
param principalId string
param principalName string
resource sqlServerAdminManagedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { name: take('sql-admin-${uniqueString(resourceGroup().id)}', 63) location: location}
resource sql 'Microsoft.Sql/servers@2024-05-01-preview' = { name: take('sql-${uniqueString(resourceGroup().id)}', 63) location: location properties: { administrators: { administratorType: 'ActiveDirectory' login: sqlServerAdminManagedIdentity.name sid: sqlServerAdminManagedIdentity.properties.principalId tenantId: subscription().tenantId azureADOnlyAuthentication: true } minimalTlsVersion: '1.2' publicNetworkAccess: 'Enabled' version: '12.0' } tags: { 'aspire-resource-name': 'sql' }}
resource sqlFirewallRule_AllowAllAzureIps 'Microsoft.Sql/servers/firewallRules@2024-05-01-preview' = { name: 'AllowAllAzureIps' properties: { endIpAddress: '0.0.0.0' startIpAddress: '0.0.0.0' } parent: sql}
resource database 'Microsoft.Sql/servers/databases@2024-05-01-preview' = { name: 'database' location: location properties: { freeLimitExhaustionBehavior: 'AutoPause' useFreeLimit: true } sku: { name: 'GP_S_Gen5_2' } parent: sql}
output sqlServerFqdn string = sql.properties.fullyQualifiedDomainName
output name string = sql.name
output sqlServerAdminName string = sql.properties.administrators.loginThe generated Bicep provisions an Azure SQL Server with a managed identity administrator, TLS 1.2 minimum, and a General Purpose Serverless database with the Azure free offer enabled.
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 are reflected in the generated files.
Customize provisioning infrastructure
Section titled “Customize provisioning infrastructure”All Aspire Azure resources are subclasses of the AzureProvisioningResource type. This type enables customization of the generated Bicep by providing a fluent API to configure the Azure resources using the ConfigureInfrastructure API. For example, you can configure the sku, version, and more. The following example demonstrates how to customize the Azure SQL Database resource:
var builder = DistributedApplication.CreateBuilder(args);
var sql = builder.AddAzureSqlServer("sql") .ConfigureInfrastructure(infra => { var sqlServer = infra.GetProvisionableResources() .OfType<SqlServer>() .Single();
sqlServer.MinTlsVersion = SqlMinimalTlsVersion.Tls1_3;
var database = infra.GetProvisionableResources() .OfType<SqlDatabase>() .Single();
database.Sku = new SqlSku { Name = "HS_Gen5_2" }; // Hyperscale }) .AddDatabase("database");
builder.Build().Run();The preceding code:
- Chains a call to the
ConfigureInfrastructureAPI where theinfraparameter is an instance ofAzureResourceInfrastructure. - Retrieves provisionable resources by calling
GetProvisionableResources. - Configures the
SqlServerwith TLS 1.3 minimum. - Configures the
SqlDatabasewith a Hyperscale SKU instead of the default serverless tier.
For more information, see Customize Azure resources. For the full list of configurable properties, see the Azure.Provisioning.Sql API documentation.
Admin deployment script
Section titled “Admin deployment script”When you deploy an Azure SQL Server resource, Aspire runs a deployment script that grants your application’s managed identity access to the SQL database. This script executes on an Azure Container Instance (ACI) and connects to the SQL Server to create the necessary database user and role assignments.
Private endpoint considerations
Section titled “Private endpoint considerations”When you add a private endpoint to the Azure SQL Server resource, public network access is disabled on the SQL Server. For the deployment script to execute successfully, the ACI it runs on needs access to the SQL Server through the private network. This requires:
- A subnet delegated to ACI, so the container runs inside the virtual network.
- An Azure Storage account, so ACI can mount a file share for the deployment script contents and logs.
Aspire automatically creates both of these resources when a private endpoint is detected on the Azure SQL Server.
Customize the deployment script behavior
Section titled “Customize the deployment script behavior”You can modify the default behavior in the following ways:
Disable the deployment script
Section titled “Disable the deployment script”Call ClearDefaultRoleAssignments (or clearDefaultRoleAssignments) to disable the deployment script entirely:
var builder = DistributedApplication.CreateBuilder(args);
var sql = builder.AddAzureSqlServer("sql").ClearDefaultRoleAssignments();
builder.Build().Run();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 sql: AzureSqlServerResource
sql = await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addAzureSqlServer(name: string): AzureSqlServerResource
Adds an Azure SQL Database (server) resource to the application model.
addAzureSqlServer("sql");await const sql: AzureSqlServerResource
sql.AzureBicepResource.clearDefaultRoleAssignments(): IAzureResource
Clears all default role assignments for the specified Azure resource.
clearDefaultRoleAssignments();
await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.build(): DistributedApplication
Builds the distributed application
build().DistributedApplication.run(cancellationToken?: cancellationToken): void
Runs the distributed application
run();Specify a custom subnet
Section titled “Specify a custom subnet”Call WithAdminDeploymentScriptSubnet (or withAdminDeploymentScriptSubnet) to provide your own subnet for the deployment script container:
var builder = DistributedApplication.CreateBuilder(args);
var vnet = builder.AddAzureVirtualNetwork("vnet");var peSubnet = vnet.AddSubnet("pe-subnet", "10.0.2.0/24");var aciSubnet = vnet.AddSubnet("aci-subnet", "10.0.3.0/29");
var sql = builder.AddAzureSqlServer("sql").WithAdminDeploymentScriptSubnet(aciSubnet);var db = sql.AddDatabase("database");
peSubnet.AddPrivateEndpoint(sql);
builder.Build().Run();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 vnet: AzureVirtualNetworkResource
vnet = await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addAzureVirtualNetwork(name: string, options?: { addressPrefix?: string | ParameterResource;}): AzureVirtualNetworkResource (+1 overload)
Adds an Azure Virtual Network resource to the application model.
addAzureVirtualNetwork("vnet");const const peSubnet: AzureSubnetResource
peSubnet = await const vnet: AzureVirtualNetworkResource
vnet.AzureVirtualNetworkResource.addSubnet(name: string, addressPrefix: string | ParameterResource, options?: { subnetName?: string;} | undefined): AzureSubnetResource (+1 overload)
Adds an Azure subnet resource to an Azure Virtual Network resource.
addSubnet("pe-subnet", "10.0.2.0/24");const const aciSubnet: AzureSubnetResource
aciSubnet = await const vnet: AzureVirtualNetworkResource
vnet.AzureVirtualNetworkResource.addSubnet(name: string, addressPrefix: string | ParameterResource, options?: { subnetName?: string;} | undefined): AzureSubnetResource (+1 overload)
Adds an Azure subnet resource to an Azure Virtual Network resource.
addSubnet("aci-subnet", "10.0.3.0/29");
const const sql: AzureSqlServerResource
sql = await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addAzureSqlServer(name: string): AzureSqlServerResource
Adds an Azure SQL Database (server) resource to the application model.
addAzureSqlServer("sql");await const sql: AzureSqlServerResource
sql.AzureSqlServerResource.withAdminDeploymentScriptSubnet(subnet: AzureSubnetResource): AzureSqlServerResource
Configures the Azure SQL Server to use the specified subnet for deployment script execution.
withAdminDeploymentScriptSubnet(const aciSubnet: AzureSubnetResource
aciSubnet);const const db: AzureSqlDatabaseResource
db = await const sql: AzureSqlServerResource
sql.AzureSqlServerResource.addDatabase(name: string, options?: { databaseName?: string;}): AzureSqlDatabaseResource (+1 overload)
Adds an Azure SQL Database to the application model. The Free Offer option will be used when deploying the resource in Azure
addDatabase("database");
await const peSubnet: AzureSubnetResource
peSubnet.AzureSubnetResource.addPrivateEndpoint(target: IAzurePrivateEndpointTarget): AzurePrivateEndpointResource
Adds an Azure Private Endpoint resource to the subnet.
addPrivateEndpoint(const sql: AzureSqlServerResource
sql);
await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.build(): DistributedApplication
Builds the distributed application
build().DistributedApplication.run(cancellationToken?: cancellationToken): void
Runs the distributed application
run();Specify a custom storage account
Section titled “Specify a custom storage account”Call WithAdminDeploymentScriptStorage (or withAdminDeploymentScriptStorage) to provide your own storage account for the deployment script:
var builder = DistributedApplication.CreateBuilder(args);
var vnet = builder.AddAzureVirtualNetwork("vnet");var peSubnet = vnet.AddSubnet("pe-subnet", "10.0.2.0/24");
var storage = builder.AddAzureStorage("scriptstorage");var sql = builder.AddAzureSqlServer("sql").WithAdminDeploymentScriptStorage(storage);var db = sql.AddDatabase("database");
peSubnet.AddPrivateEndpoint(sql);
builder.Build().Run();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 vnet: AzureVirtualNetworkResource
vnet = await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addAzureVirtualNetwork(name: string, options?: { addressPrefix?: string | ParameterResource;}): AzureVirtualNetworkResource (+1 overload)
Adds an Azure Virtual Network resource to the application model.
addAzureVirtualNetwork("vnet");const const peSubnet: AzureSubnetResource
peSubnet = await const vnet: AzureVirtualNetworkResource
vnet.AzureVirtualNetworkResource.addSubnet(name: string, addressPrefix: string | ParameterResource, options?: { subnetName?: string;} | undefined): AzureSubnetResource (+1 overload)
Adds an Azure subnet resource to an Azure Virtual Network resource.
addSubnet("pe-subnet", "10.0.2.0/24");
const const storage: AzureStorageResource
storage = await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addAzureStorage(name: string): AzureStorageResource
Adds an Azure Storage resource to the application model. This resource can be used to create Azure blob, table, and queue resources.
addAzureStorage("scriptstorage");const const sql: AzureSqlServerResource
sql = await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.addAzureSqlServer(name: string): AzureSqlServerResource
Adds an Azure SQL Database (server) resource to the application model.
addAzureSqlServer("sql");await const sql: AzureSqlServerResource
sql.AzureSqlServerResource.withAdminDeploymentScriptStorage(storage: AzureStorageResource): AzureSqlServerResource
Configures the Azure SQL Server to use the specified storage account for deployment script execution.
withAdminDeploymentScriptStorage(const storage: AzureStorageResource
storage);const const db: AzureSqlDatabaseResource
db = await const sql: AzureSqlServerResource
sql.AzureSqlServerResource.addDatabase(name: string, options?: { databaseName?: string;}): AzureSqlDatabaseResource (+1 overload)
Adds an Azure SQL Database to the application model. The Free Offer option will be used when deploying the resource in Azure
addDatabase("database");
await const peSubnet: AzureSubnetResource
peSubnet.AzureSubnetResource.addPrivateEndpoint(target: IAzurePrivateEndpointTarget): AzurePrivateEndpointResource
Adds an Azure Private Endpoint resource to the subnet.
addPrivateEndpoint(const sql: AzureSqlServerResource
sql);
await const builder: IDistributedApplicationBuilder
builder.IDistributedApplicationBuilder.build(): DistributedApplication
Builds the distributed application
build().DistributedApplication.run(cancellationToken?: cancellationToken): void
Runs the distributed application
run();Connection properties
Section titled “Connection properties”For the full reference of Azure SQL Database connection properties — and how consuming apps in C#, TypeScript, Python, and Go read them — see Connect to Azure SQL Database.
Hosting integration health checks
Section titled “Hosting integration health checks”The Azure SQL Database hosting integration automatically adds a health check for the Azure SQL Server resource. The health check verifies that the SQL Server instance is running and that a connection can be established to it.
The hosting integration relies on the 📦 AspNetCore.HealthChecks.SqlServer NuGet package.