Skip to content
Docs Try Aspire
Docs Try

Set up Azure Database for PostgreSQL in the AppHost

Azure Database for PostgreSQL logo

This article is the reference for the Aspire Azure PostgreSQL Hosting integration. It enumerates the AppHost APIs — with examples for both AppHost.cs and apphost.mts — that you use to model Azure Database for PostgreSQL flexible server and database resources in your AppHost project.

If you’re new to the Azure PostgreSQL integration, start with the Get started with Azure Database for PostgreSQL integrations guide. For how consuming apps read the connection information this page exposes, see Connect to Azure PostgreSQL. For the PostgreSQL Entity Framework Core (EF Core) client integration, see Get started with the PostgreSQL Entity Framework Core integrations.

To start building an Aspire app that uses Azure Database for PostgreSQL, install the 📦 Aspire.Hosting.Azure.PostgreSQL NuGet package:

Terminal
aspire add azure-postgres

Learn more about aspire add in the command reference.

Or, choose a manual installation approach:

C# — AppHost.cs
#:package Aspire.Hosting.Azure.PostgreSQL@*
XML — AppHost.csproj
<PackageReference Include="Aspire.Hosting.Azure.PostgreSQL" Version="*" />

Add an Azure Database for PostgreSQL resource

Section titled “Add an Azure Database for PostgreSQL resource”

Once you’ve installed the hosting integration in your AppHost project, you can add a PostgreSQL flexible server resource and then add a database resource:

C# — AppHost.cs
var builder = DistributedApplication.CreateBuilder(args);
var postgres = builder.AddAzurePostgresFlexibleServer("postgres");
var postgresdb = postgres.AddDatabase("postgresdb");
var exampleProject = builder.AddProject<Projects.ExampleProject>("apiservice")
.WaitFor(postgresdb)
.WithReference(postgresdb);
// After adding all resources, run the app...
builder.Build().Run();

The preceding code adds an Azure PostgreSQL flexible server resource named postgres with a database named postgresdb. The withReference / WithReference call injects the connection information into the consuming project.

You can add multiple named databases to the same flexible server resource:

C# — AppHost.cs
var builder = DistributedApplication.CreateBuilder(args);
var postgres = builder.AddAzurePostgresFlexibleServer("postgres");
var catalogDb = postgres.AddDatabase("catalogdb");
var ordersDb = postgres.AddDatabase("ordersdb");
builder.AddProject<Projects.CatalogService>("catalog")
.WithReference(catalogDb)
.WaitFor(catalogDb);
builder.AddProject<Projects.OrdersService>("orders")
.WithReference(ordersDb)
.WaitFor(ordersDb);
// After adding all resources, run the app...

You can also customize the underlying database name (as distinct from the Aspire resource name) by passing databaseName in the options:

C# — AppHost.cs
var postgresdb = postgres.AddDatabase("postgresdb", databaseName: "app_catalog");

Run as a local container during development

Section titled “Run as a local container during development”

The Azure PostgreSQL hosting integration supports running the PostgreSQL server as a local Docker container. This is beneficial for local development and testing — you get a real PostgreSQL server without needing an Azure subscription or connection to an existing Azure PostgreSQL instance.

C# — AppHost.cs
var builder = DistributedApplication.CreateBuilder(args);
var postgres = builder.AddAzurePostgresFlexibleServer("postgres")
.RunAsContainer();
var postgresdb = postgres.AddDatabase("postgresdb");
var exampleProject = builder.AddProject<Projects.ExampleProject>("apiservice")
.WithReference(postgresdb)
.WaitFor(postgresdb);
// After adding all resources, run the app...
builder.Build().Run();

When RunAsContainer / runAsContainer is called, Aspire uses the docker.io/library/postgres container image and generates credentials automatically. The same consuming app code and environment variable names work in both local-container and Azure modes.

Cross-reference: local-container vs Azure PostgreSQL

Section titled “Cross-reference: local-container vs Azure PostgreSQL”

If you are developing against a local container and want to switch to Azure PostgreSQL for staging or production, change AddPostgres to AddAzurePostgresFlexibleServer in the AppHost. The connection information injected into consuming apps uses the same environment variable names, so no application code changes are required.

For a comparison of the two hosting integrations, see PostgreSQL Hosting integration.

Connect to an existing Azure PostgreSQL flexible server

Section titled “Connect to an existing Azure PostgreSQL flexible server”

If you have an existing Azure Database for PostgreSQL Flexible Server that you want to connect to rather than provisioning a new one, use AsExisting / asExisting:

C# — AppHost.cs
var builder = DistributedApplication.CreateBuilder(args);
var existingPostgresName = builder.AddParameter("existingPostgresName");
var existingPostgresResourceGroup = builder.AddParameter("existingPostgresResourceGroup");
var postgres = builder.AddAzurePostgresFlexibleServer("postgres")
.AsExisting(existingPostgresName, existingPostgresResourceGroup);
builder.AddProject<Projects.ExampleProject>("apiservice")
.WithReference(postgres);
// After adding all resources, run the app...
builder.Build().Run();

For more information on treating Azure resources as existing, see Use existing Azure resources.

By default, the Azure PostgreSQL flexible server is configured to use Microsoft Entra ID authentication — no username or password is stored in your app configuration. If you need password authentication (for example, to connect with a legacy client that doesn’t support Entra tokens), call WithPasswordAuthentication / withPasswordAuthentication:

C# — AppHost.cs
var builder = DistributedApplication.CreateBuilder(args);
var username = builder.AddParameter("username", secret: true);
var password = builder.AddParameter("password", secret: true);
var postgres = builder.AddAzurePostgresFlexibleServer("postgres")
.WithPasswordAuthentication(username, password);
var postgresdb = postgres.AddDatabase("postgresdb");
builder.AddProject<Projects.ExampleProject>("apiservice")
.WithReference(postgresdb)
.WaitFor(postgresdb);
// After adding all resources, run the app...
builder.Build().Run();

When password authentication is enabled, the Username and Password connection properties are also injected into consuming apps. See Connect to Azure PostgreSQL for the full property reference.

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 PostgreSQL resource, the following Bicep is generated:

Generated Bicep — postgres.bicep
@description('The location for the resource(s) to be deployed.')
param location string = resourceGroup().location
resource postgres_flexible 'Microsoft.DBforPostgreSQL/flexibleServers@2024-08-01' = {
name: take('postgresflexible-${uniqueString(resourceGroup().id)}', 63)
location: location
properties: {
authConfig: {
activeDirectoryAuth: 'Enabled'
passwordAuth: 'Disabled'
}
availabilityZone: '1'
backup: {
backupRetentionDays: 7
geoRedundantBackup: 'Disabled'
}
highAvailability: {
mode: 'Disabled'
}
storage: {
storageSizeGB: 32
}
version: '16'
}
sku: {
name: 'Standard_B1ms'
tier: 'Burstable'
}
tags: {
'aspire-resource-name': 'postgres-flexible'
}
}
resource postgreSqlFirewallRule_AllowAllAzureIps 'Microsoft.DBforPostgreSQL/flexibleServers/firewallRules@2024-08-01' = {
name: 'AllowAllAzureIps'
properties: {
endIpAddress: '0.0.0.0'
startIpAddress: '0.0.0.0'
}
parent: postgres_flexible
}
output connectionString string = 'Host=${postgres_flexible.properties.fullyQualifiedDomainName}'
output name string = postgres_flexible.name

Additionally, role assignments are created for the Azure resource in a separate module:

Generated Bicep — postgres-flexible-roles.bicep
@description('The location for the resource(s) to be deployed.')
param location string = resourceGroup().location
param postgres_flexible_outputs_name string
param principalType string
param principalId string
param principalName string
resource postgres_flexible 'Microsoft.DBforPostgreSQL/flexibleServers@2024-08-01' existing = {
name: postgres_flexible_outputs_name
}
resource postgres_flexible_admin 'Microsoft.DBforPostgreSQL/flexibleServers/administrators@2024-08-01' = {
name: principalId
properties: {
principalName: principalName
principalType: principalType
}
parent: postgres_flexible
}

The roles Bicep creates an administrator record on the flexible server, granting the deploying principal role-based access. This is the mechanism that underpins Entra ID (managed identity) authentication — no password is required because the principal’s identity is used to obtain short-lived tokens at runtime.

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.

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:

C# — AppHost.cs
var builder = DistributedApplication.CreateBuilder(args);
builder.AddAzurePostgresFlexibleServer("postgres")
.ConfigureInfrastructure(infra =>
{
var flexibleServer = infra.GetProvisionableResources()
.OfType<PostgreSqlFlexibleServer>()
.Single();
flexibleServer.Sku = new PostgreSqlFlexibleServerSku
{
Tier = PostgreSqlFlexibleServerSkuTier.Burstable,
};
flexibleServer.HighAvailability = new PostgreSqlFlexibleServerHighAvailability
{
Mode = PostgreSqlFlexibleServerHighAvailabilityMode.ZoneRedundant,
StandbyAvailabilityZone = "2",
};
flexibleServer.Tags.Add("ExampleKey", "Example value");
});
// After adding all resources, run the app...
builder.Build().Run();

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 PostgreSqlFlexibleServer is retrieved.
    • The sku is set with PostgreSqlFlexibleServerSkuTier.Burstable.
    • The high availability properties are set with PostgreSqlFlexibleServerHighAvailabilityMode.ZoneRedundant in standby availability zone "2".
    • A tag is added to the flexible server with a key of ExampleKey and a value of Example value.

There are many more configuration options available to customize the PostgreSQL resource. For more information, see Azure.Provisioning customization.

Database creation after initial deployment

Section titled “Database creation after initial deployment”

When you call AddDatabase / addDatabase on an Azure PostgreSQL resource, Aspire provisions the database during the first deployment. On subsequent deployments with azd up, only the server-level Bicep is redeployed — databases that already exist are not recreated or deleted.

If you need to add a new database to an existing server, redeploy your application with the updated AppHost code or manually create the database by using the Azure portal or the PostgreSQL CLI:

Bash — Create database manually
az postgres flexible-server db create \
--resource-group <resource-group> \
--server-name <server-name> \
--database-name <new-database-name>