Manage Azure Database for PostgreSQL Migrations

The azure-native:dbforpostgresql:Migration resource, part of the Pulumi Azure Native provider, orchestrates PostgreSQL database migrations from various source types to Azure Database for PostgreSQL Flexible Server. This guide focuses on four capabilities: validation-only migrations for compatibility checking, on-premises and cross-cloud source configuration, private endpoint routing, and role and permission migration.

Migrations require both source and target PostgreSQL servers to exist, with appropriate network connectivity and admin credentials. The examples are intentionally small. Combine them with your own server infrastructure, network configuration, and credential management.

Validate migration compatibility without moving data

Teams planning database migrations often start by validating schema compatibility and identifying potential issues before committing to data transfer.

import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";

const migration = new azure_native.dbforpostgresql.Migration("migration", {
    dbsToMigrate: [
        "exampledatabase1",
        "exampledatabase2",
        "exampledatabase3",
        "exampledatabase4",
    ],
    location: "westus",
    migrationMode: azure_native.dbforpostgresql.MigrationMode.Offline,
    migrationName: "examplemigration",
    migrationOption: azure_native.dbforpostgresql.MigrationOption.Validate,
    overwriteDbsInTarget: azure_native.dbforpostgresql.OverwriteDbsInTargetEnum.True,
    resourceGroupName: "exampleresourcegroup",
    secretParameters: {
        adminCredentials: {
            sourceServerPassword: "examplesourcepassword",
            targetServerPassword: "exampletargetpassword",
        },
    },
    sourceDbServerResourceId: "/subscriptions/ffffffff-ffff-ffff-ffff-ffffffffffff/resourceGroups/exampleresourcegroup/providers/Microsoft.DBForPostgreSql/servers/examplesource",
    targetDbServerName: "exampletarget",
});
import pulumi
import pulumi_azure_native as azure_native

migration = azure_native.dbforpostgresql.Migration("migration",
    dbs_to_migrate=[
        "exampledatabase1",
        "exampledatabase2",
        "exampledatabase3",
        "exampledatabase4",
    ],
    location="westus",
    migration_mode=azure_native.dbforpostgresql.MigrationMode.OFFLINE,
    migration_name="examplemigration",
    migration_option=azure_native.dbforpostgresql.MigrationOption.VALIDATE,
    overwrite_dbs_in_target=azure_native.dbforpostgresql.OverwriteDbsInTargetEnum.TRUE,
    resource_group_name="exampleresourcegroup",
    secret_parameters={
        "admin_credentials": {
            "source_server_password": "examplesourcepassword",
            "target_server_password": "exampletargetpassword",
        },
    },
    source_db_server_resource_id="/subscriptions/ffffffff-ffff-ffff-ffff-ffffffffffff/resourceGroups/exampleresourcegroup/providers/Microsoft.DBForPostgreSql/servers/examplesource",
    target_db_server_name="exampletarget")
package main

import (
	dbforpostgresql "github.com/pulumi/pulumi-azure-native-sdk/dbforpostgresql/v3"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := dbforpostgresql.NewMigration(ctx, "migration", &dbforpostgresql.MigrationArgs{
			DbsToMigrate: pulumi.StringArray{
				pulumi.String("exampledatabase1"),
				pulumi.String("exampledatabase2"),
				pulumi.String("exampledatabase3"),
				pulumi.String("exampledatabase4"),
			},
			Location:             pulumi.String("westus"),
			MigrationMode:        pulumi.String(dbforpostgresql.MigrationModeOffline),
			MigrationName:        pulumi.String("examplemigration"),
			MigrationOption:      pulumi.String(dbforpostgresql.MigrationOptionValidate),
			OverwriteDbsInTarget: pulumi.String(dbforpostgresql.OverwriteDbsInTargetEnumTrue),
			ResourceGroupName:    pulumi.String("exampleresourcegroup"),
			SecretParameters: &dbforpostgresql.MigrationSecretParametersArgs{
				AdminCredentials: &dbforpostgresql.AdminCredentialsArgs{
					SourceServerPassword: pulumi.String("examplesourcepassword"),
					TargetServerPassword: pulumi.String("exampletargetpassword"),
				},
			},
			SourceDbServerResourceId: pulumi.String("/subscriptions/ffffffff-ffff-ffff-ffff-ffffffffffff/resourceGroups/exampleresourcegroup/providers/Microsoft.DBForPostgreSql/servers/examplesource"),
			TargetDbServerName:       pulumi.String("exampletarget"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;

return await Deployment.RunAsync(() => 
{
    var migration = new AzureNative.DBforPostgreSQL.Migration("migration", new()
    {
        DbsToMigrate = new[]
        {
            "exampledatabase1",
            "exampledatabase2",
            "exampledatabase3",
            "exampledatabase4",
        },
        Location = "westus",
        MigrationMode = AzureNative.DBforPostgreSQL.MigrationMode.Offline,
        MigrationName = "examplemigration",
        MigrationOption = AzureNative.DBforPostgreSQL.MigrationOption.Validate,
        OverwriteDbsInTarget = AzureNative.DBforPostgreSQL.OverwriteDbsInTargetEnum.True,
        ResourceGroupName = "exampleresourcegroup",
        SecretParameters = new AzureNative.DBforPostgreSQL.Inputs.MigrationSecretParametersArgs
        {
            AdminCredentials = new AzureNative.DBforPostgreSQL.Inputs.AdminCredentialsArgs
            {
                SourceServerPassword = "examplesourcepassword",
                TargetServerPassword = "exampletargetpassword",
            },
        },
        SourceDbServerResourceId = "/subscriptions/ffffffff-ffff-ffff-ffff-ffffffffffff/resourceGroups/exampleresourcegroup/providers/Microsoft.DBForPostgreSql/servers/examplesource",
        TargetDbServerName = "exampletarget",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.dbforpostgresql.Migration;
import com.pulumi.azurenative.dbforpostgresql.MigrationArgs;
import com.pulumi.azurenative.dbforpostgresql.inputs.MigrationSecretParametersArgs;
import com.pulumi.azurenative.dbforpostgresql.inputs.AdminCredentialsArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var migration = new Migration("migration", MigrationArgs.builder()
            .dbsToMigrate(            
                "exampledatabase1",
                "exampledatabase2",
                "exampledatabase3",
                "exampledatabase4")
            .location("westus")
            .migrationMode("Offline")
            .migrationName("examplemigration")
            .migrationOption("Validate")
            .overwriteDbsInTarget("True")
            .resourceGroupName("exampleresourcegroup")
            .secretParameters(MigrationSecretParametersArgs.builder()
                .adminCredentials(AdminCredentialsArgs.builder()
                    .sourceServerPassword("examplesourcepassword")
                    .targetServerPassword("exampletargetpassword")
                    .build())
                .build())
            .sourceDbServerResourceId("/subscriptions/ffffffff-ffff-ffff-ffff-ffffffffffff/resourceGroups/exampleresourcegroup/providers/Microsoft.DBForPostgreSql/servers/examplesource")
            .targetDbServerName("exampletarget")
            .build());

    }
}
resources:
  migration:
    type: azure-native:dbforpostgresql:Migration
    properties:
      dbsToMigrate:
        - exampledatabase1
        - exampledatabase2
        - exampledatabase3
        - exampledatabase4
      location: westus
      migrationMode: Offline
      migrationName: examplemigration
      migrationOption: Validate
      overwriteDbsInTarget: True
      resourceGroupName: exampleresourcegroup
      secretParameters:
        adminCredentials:
          sourceServerPassword: examplesourcepassword
          targetServerPassword: exampletargetpassword
      sourceDbServerResourceId: /subscriptions/ffffffff-ffff-ffff-ffff-ffffffffffff/resourceGroups/exampleresourcegroup/providers/Microsoft.DBForPostgreSql/servers/examplesource
      targetDbServerName: exampletarget

The migrationOption property set to “Validate” runs compatibility checks without transferring data. The migration connects to both source and target using credentials in secretParameters, examines the databases listed in dbsToMigrate, and reports any schema incompatibilities or blocking issues. The migrationMode property controls whether the eventual migration runs offline (with downtime) or online (with minimal downtime through replication).

Migrate from on-premises PostgreSQL servers

Organizations moving from on-premises infrastructure to Azure need to specify connection details differently than when migrating between Azure resources.

import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";

const migration = new azure_native.dbforpostgresql.Migration("migration", {
    dbsToMigrate: [
        "exampledatabase1",
        "exampledatabase2",
        "exampledatabase3",
        "exampledatabase4",
    ],
    location: "westus",
    migrationMode: azure_native.dbforpostgresql.MigrationMode.Offline,
    migrationName: "examplemigration",
    migrationOption: azure_native.dbforpostgresql.MigrationOption.ValidateAndMigrate,
    overwriteDbsInTarget: azure_native.dbforpostgresql.OverwriteDbsInTargetEnum.True,
    resourceGroupName: "exampleresourcegroup",
    secretParameters: {
        adminCredentials: {
            sourceServerPassword: "examplesourcepassword",
            targetServerPassword: "exampletargetpassword",
        },
    },
    sourceDbServerResourceId: "examplesource:5432@exampleuser",
    sourceType: azure_native.dbforpostgresql.SourceType.OnPremises,
    sslMode: azure_native.dbforpostgresql.SslMode.Prefer,
    targetDbServerName: "exampletarget",
});
import pulumi
import pulumi_azure_native as azure_native

migration = azure_native.dbforpostgresql.Migration("migration",
    dbs_to_migrate=[
        "exampledatabase1",
        "exampledatabase2",
        "exampledatabase3",
        "exampledatabase4",
    ],
    location="westus",
    migration_mode=azure_native.dbforpostgresql.MigrationMode.OFFLINE,
    migration_name="examplemigration",
    migration_option=azure_native.dbforpostgresql.MigrationOption.VALIDATE_AND_MIGRATE,
    overwrite_dbs_in_target=azure_native.dbforpostgresql.OverwriteDbsInTargetEnum.TRUE,
    resource_group_name="exampleresourcegroup",
    secret_parameters={
        "admin_credentials": {
            "source_server_password": "examplesourcepassword",
            "target_server_password": "exampletargetpassword",
        },
    },
    source_db_server_resource_id="examplesource:5432@exampleuser",
    source_type=azure_native.dbforpostgresql.SourceType.ON_PREMISES,
    ssl_mode=azure_native.dbforpostgresql.SslMode.PREFER,
    target_db_server_name="exampletarget")
package main

import (
	dbforpostgresql "github.com/pulumi/pulumi-azure-native-sdk/dbforpostgresql/v3"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := dbforpostgresql.NewMigration(ctx, "migration", &dbforpostgresql.MigrationArgs{
			DbsToMigrate: pulumi.StringArray{
				pulumi.String("exampledatabase1"),
				pulumi.String("exampledatabase2"),
				pulumi.String("exampledatabase3"),
				pulumi.String("exampledatabase4"),
			},
			Location:             pulumi.String("westus"),
			MigrationMode:        pulumi.String(dbforpostgresql.MigrationModeOffline),
			MigrationName:        pulumi.String("examplemigration"),
			MigrationOption:      pulumi.String(dbforpostgresql.MigrationOptionValidateAndMigrate),
			OverwriteDbsInTarget: pulumi.String(dbforpostgresql.OverwriteDbsInTargetEnumTrue),
			ResourceGroupName:    pulumi.String("exampleresourcegroup"),
			SecretParameters: &dbforpostgresql.MigrationSecretParametersArgs{
				AdminCredentials: &dbforpostgresql.AdminCredentialsArgs{
					SourceServerPassword: pulumi.String("examplesourcepassword"),
					TargetServerPassword: pulumi.String("exampletargetpassword"),
				},
			},
			SourceDbServerResourceId: pulumi.String("examplesource:5432@exampleuser"),
			SourceType:               pulumi.String(dbforpostgresql.SourceTypeOnPremises),
			SslMode:                  pulumi.String(dbforpostgresql.SslModePrefer),
			TargetDbServerName:       pulumi.String("exampletarget"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;

return await Deployment.RunAsync(() => 
{
    var migration = new AzureNative.DBforPostgreSQL.Migration("migration", new()
    {
        DbsToMigrate = new[]
        {
            "exampledatabase1",
            "exampledatabase2",
            "exampledatabase3",
            "exampledatabase4",
        },
        Location = "westus",
        MigrationMode = AzureNative.DBforPostgreSQL.MigrationMode.Offline,
        MigrationName = "examplemigration",
        MigrationOption = AzureNative.DBforPostgreSQL.MigrationOption.ValidateAndMigrate,
        OverwriteDbsInTarget = AzureNative.DBforPostgreSQL.OverwriteDbsInTargetEnum.True,
        ResourceGroupName = "exampleresourcegroup",
        SecretParameters = new AzureNative.DBforPostgreSQL.Inputs.MigrationSecretParametersArgs
        {
            AdminCredentials = new AzureNative.DBforPostgreSQL.Inputs.AdminCredentialsArgs
            {
                SourceServerPassword = "examplesourcepassword",
                TargetServerPassword = "exampletargetpassword",
            },
        },
        SourceDbServerResourceId = "examplesource:5432@exampleuser",
        SourceType = AzureNative.DBforPostgreSQL.SourceType.OnPremises,
        SslMode = AzureNative.DBforPostgreSQL.SslMode.Prefer,
        TargetDbServerName = "exampletarget",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.dbforpostgresql.Migration;
import com.pulumi.azurenative.dbforpostgresql.MigrationArgs;
import com.pulumi.azurenative.dbforpostgresql.inputs.MigrationSecretParametersArgs;
import com.pulumi.azurenative.dbforpostgresql.inputs.AdminCredentialsArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var migration = new Migration("migration", MigrationArgs.builder()
            .dbsToMigrate(            
                "exampledatabase1",
                "exampledatabase2",
                "exampledatabase3",
                "exampledatabase4")
            .location("westus")
            .migrationMode("Offline")
            .migrationName("examplemigration")
            .migrationOption("ValidateAndMigrate")
            .overwriteDbsInTarget("True")
            .resourceGroupName("exampleresourcegroup")
            .secretParameters(MigrationSecretParametersArgs.builder()
                .adminCredentials(AdminCredentialsArgs.builder()
                    .sourceServerPassword("examplesourcepassword")
                    .targetServerPassword("exampletargetpassword")
                    .build())
                .build())
            .sourceDbServerResourceId("examplesource:5432@exampleuser")
            .sourceType("OnPremises")
            .sslMode("Prefer")
            .targetDbServerName("exampletarget")
            .build());

    }
}
resources:
  migration:
    type: azure-native:dbforpostgresql:Migration
    properties:
      dbsToMigrate:
        - exampledatabase1
        - exampledatabase2
        - exampledatabase3
        - exampledatabase4
      location: westus
      migrationMode: Offline
      migrationName: examplemigration
      migrationOption: ValidateAndMigrate
      overwriteDbsInTarget: True
      resourceGroupName: exampleresourcegroup
      secretParameters:
        adminCredentials:
          sourceServerPassword: examplesourcepassword
          targetServerPassword: exampletargetpassword
      sourceDbServerResourceId: examplesource:5432@exampleuser
      sourceType: OnPremises
      sslMode: Prefer
      targetDbServerName: exampletarget

When sourceType is “OnPremises”, the sourceDbServerResourceId uses a connection string format (“hostname:port@username”) instead of an Azure resource ID. The sslMode property controls TLS requirements; “Prefer” attempts encrypted connections but falls back to unencrypted if necessary. Setting migrationOption to “ValidateAndMigrate” runs validation checks and immediately proceeds to data transfer if no blockers are found.

Route migration through a private endpoint

Migrations involving private networks or VPN-connected sources require a migration instance that acts as a bridge between the source and target.

import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";

const migration = new azure_native.dbforpostgresql.Migration("migration", {
    dbsToMigrate: [
        "exampledatabase1",
        "exampledatabase2",
        "exampledatabase3",
        "exampledatabase4",
    ],
    location: "westus",
    migrationInstanceResourceId: "/subscriptions/ffffffff-ffff-ffff-ffff-ffffffffffff/resourceGroups/exampleresourcegroup/providers/Microsoft.DBForPostgreSql/flexibleServers/examplesourcemigration",
    migrationMode: azure_native.dbforpostgresql.MigrationMode.Offline,
    migrationName: "examplemigration",
    overwriteDbsInTarget: azure_native.dbforpostgresql.OverwriteDbsInTargetEnum.True,
    resourceGroupName: "exampleresourcegroup",
    secretParameters: {
        adminCredentials: {
            sourceServerPassword: "examplesourcepassword",
            targetServerPassword: "exampletargetpassword",
        },
    },
    sourceDbServerResourceId: "/subscriptions/ffffffff-ffff-ffff-ffff-ffffffffffff/resourceGroups/exampleresourcegroup/providers/Microsoft.DBForPostgreSql/servers/examplesource",
    targetDbServerName: "exampletarget",
});
import pulumi
import pulumi_azure_native as azure_native

migration = azure_native.dbforpostgresql.Migration("migration",
    dbs_to_migrate=[
        "exampledatabase1",
        "exampledatabase2",
        "exampledatabase3",
        "exampledatabase4",
    ],
    location="westus",
    migration_instance_resource_id="/subscriptions/ffffffff-ffff-ffff-ffff-ffffffffffff/resourceGroups/exampleresourcegroup/providers/Microsoft.DBForPostgreSql/flexibleServers/examplesourcemigration",
    migration_mode=azure_native.dbforpostgresql.MigrationMode.OFFLINE,
    migration_name="examplemigration",
    overwrite_dbs_in_target=azure_native.dbforpostgresql.OverwriteDbsInTargetEnum.TRUE,
    resource_group_name="exampleresourcegroup",
    secret_parameters={
        "admin_credentials": {
            "source_server_password": "examplesourcepassword",
            "target_server_password": "exampletargetpassword",
        },
    },
    source_db_server_resource_id="/subscriptions/ffffffff-ffff-ffff-ffff-ffffffffffff/resourceGroups/exampleresourcegroup/providers/Microsoft.DBForPostgreSql/servers/examplesource",
    target_db_server_name="exampletarget")
package main

import (
	dbforpostgresql "github.com/pulumi/pulumi-azure-native-sdk/dbforpostgresql/v3"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := dbforpostgresql.NewMigration(ctx, "migration", &dbforpostgresql.MigrationArgs{
			DbsToMigrate: pulumi.StringArray{
				pulumi.String("exampledatabase1"),
				pulumi.String("exampledatabase2"),
				pulumi.String("exampledatabase3"),
				pulumi.String("exampledatabase4"),
			},
			Location:                    pulumi.String("westus"),
			MigrationInstanceResourceId: pulumi.String("/subscriptions/ffffffff-ffff-ffff-ffff-ffffffffffff/resourceGroups/exampleresourcegroup/providers/Microsoft.DBForPostgreSql/flexibleServers/examplesourcemigration"),
			MigrationMode:               pulumi.String(dbforpostgresql.MigrationModeOffline),
			MigrationName:               pulumi.String("examplemigration"),
			OverwriteDbsInTarget:        pulumi.String(dbforpostgresql.OverwriteDbsInTargetEnumTrue),
			ResourceGroupName:           pulumi.String("exampleresourcegroup"),
			SecretParameters: &dbforpostgresql.MigrationSecretParametersArgs{
				AdminCredentials: &dbforpostgresql.AdminCredentialsArgs{
					SourceServerPassword: pulumi.String("examplesourcepassword"),
					TargetServerPassword: pulumi.String("exampletargetpassword"),
				},
			},
			SourceDbServerResourceId: pulumi.String("/subscriptions/ffffffff-ffff-ffff-ffff-ffffffffffff/resourceGroups/exampleresourcegroup/providers/Microsoft.DBForPostgreSql/servers/examplesource"),
			TargetDbServerName:       pulumi.String("exampletarget"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;

return await Deployment.RunAsync(() => 
{
    var migration = new AzureNative.DBforPostgreSQL.Migration("migration", new()
    {
        DbsToMigrate = new[]
        {
            "exampledatabase1",
            "exampledatabase2",
            "exampledatabase3",
            "exampledatabase4",
        },
        Location = "westus",
        MigrationInstanceResourceId = "/subscriptions/ffffffff-ffff-ffff-ffff-ffffffffffff/resourceGroups/exampleresourcegroup/providers/Microsoft.DBForPostgreSql/flexibleServers/examplesourcemigration",
        MigrationMode = AzureNative.DBforPostgreSQL.MigrationMode.Offline,
        MigrationName = "examplemigration",
        OverwriteDbsInTarget = AzureNative.DBforPostgreSQL.OverwriteDbsInTargetEnum.True,
        ResourceGroupName = "exampleresourcegroup",
        SecretParameters = new AzureNative.DBforPostgreSQL.Inputs.MigrationSecretParametersArgs
        {
            AdminCredentials = new AzureNative.DBforPostgreSQL.Inputs.AdminCredentialsArgs
            {
                SourceServerPassword = "examplesourcepassword",
                TargetServerPassword = "exampletargetpassword",
            },
        },
        SourceDbServerResourceId = "/subscriptions/ffffffff-ffff-ffff-ffff-ffffffffffff/resourceGroups/exampleresourcegroup/providers/Microsoft.DBForPostgreSql/servers/examplesource",
        TargetDbServerName = "exampletarget",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.dbforpostgresql.Migration;
import com.pulumi.azurenative.dbforpostgresql.MigrationArgs;
import com.pulumi.azurenative.dbforpostgresql.inputs.MigrationSecretParametersArgs;
import com.pulumi.azurenative.dbforpostgresql.inputs.AdminCredentialsArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var migration = new Migration("migration", MigrationArgs.builder()
            .dbsToMigrate(            
                "exampledatabase1",
                "exampledatabase2",
                "exampledatabase3",
                "exampledatabase4")
            .location("westus")
            .migrationInstanceResourceId("/subscriptions/ffffffff-ffff-ffff-ffff-ffffffffffff/resourceGroups/exampleresourcegroup/providers/Microsoft.DBForPostgreSql/flexibleServers/examplesourcemigration")
            .migrationMode("Offline")
            .migrationName("examplemigration")
            .overwriteDbsInTarget("True")
            .resourceGroupName("exampleresourcegroup")
            .secretParameters(MigrationSecretParametersArgs.builder()
                .adminCredentials(AdminCredentialsArgs.builder()
                    .sourceServerPassword("examplesourcepassword")
                    .targetServerPassword("exampletargetpassword")
                    .build())
                .build())
            .sourceDbServerResourceId("/subscriptions/ffffffff-ffff-ffff-ffff-ffffffffffff/resourceGroups/exampleresourcegroup/providers/Microsoft.DBForPostgreSql/servers/examplesource")
            .targetDbServerName("exampletarget")
            .build());

    }
}
resources:
  migration:
    type: azure-native:dbforpostgresql:Migration
    properties:
      dbsToMigrate:
        - exampledatabase1
        - exampledatabase2
        - exampledatabase3
        - exampledatabase4
      location: westus
      migrationInstanceResourceId: /subscriptions/ffffffff-ffff-ffff-ffff-ffffffffffff/resourceGroups/exampleresourcegroup/providers/Microsoft.DBForPostgreSql/flexibleServers/examplesourcemigration
      migrationMode: Offline
      migrationName: examplemigration
      overwriteDbsInTarget: True
      resourceGroupName: exampleresourcegroup
      secretParameters:
        adminCredentials:
          sourceServerPassword: examplesourcepassword
          targetServerPassword: exampletargetpassword
      sourceDbServerResourceId: /subscriptions/ffffffff-ffff-ffff-ffff-ffffffffffff/resourceGroups/exampleresourcegroup/providers/Microsoft.DBForPostgreSql/servers/examplesource
      targetDbServerName: exampletarget

The migrationInstanceResourceId references a flexible server configured to act as a migration proxy. This server must have network connectivity to both the source and target, allowing migrations to traverse private networks or VPN connections without exposing databases to the public internet.

Include database roles and permissions

Applications often depend on specific database roles, users, and permissions that must be preserved during migration.

import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";

const migration = new azure_native.dbforpostgresql.Migration("migration", {
    dbsToMigrate: [
        "exampledatabase1",
        "exampledatabase2",
        "exampledatabase3",
        "exampledatabase4",
    ],
    location: "westus",
    migrateRoles: azure_native.dbforpostgresql.MigrateRolesEnum.True,
    migrationMode: azure_native.dbforpostgresql.MigrationMode.Offline,
    migrationName: "examplemigration",
    overwriteDbsInTarget: azure_native.dbforpostgresql.OverwriteDbsInTargetEnum.True,
    resourceGroupName: "exampleresourcegroup",
    secretParameters: {
        adminCredentials: {
            sourceServerPassword: "examplesourcepassword",
            targetServerPassword: "exampletargetpassword",
        },
    },
    sourceDbServerResourceId: "/subscriptions/ffffffff-ffff-ffff-ffff-ffffffffffff/resourceGroups/exampleresourcegroup/providers/Microsoft.DBForPostgreSql/servers/examplesource",
    targetDbServerName: "exampletarget",
});
import pulumi
import pulumi_azure_native as azure_native

migration = azure_native.dbforpostgresql.Migration("migration",
    dbs_to_migrate=[
        "exampledatabase1",
        "exampledatabase2",
        "exampledatabase3",
        "exampledatabase4",
    ],
    location="westus",
    migrate_roles=azure_native.dbforpostgresql.MigrateRolesEnum.TRUE,
    migration_mode=azure_native.dbforpostgresql.MigrationMode.OFFLINE,
    migration_name="examplemigration",
    overwrite_dbs_in_target=azure_native.dbforpostgresql.OverwriteDbsInTargetEnum.TRUE,
    resource_group_name="exampleresourcegroup",
    secret_parameters={
        "admin_credentials": {
            "source_server_password": "examplesourcepassword",
            "target_server_password": "exampletargetpassword",
        },
    },
    source_db_server_resource_id="/subscriptions/ffffffff-ffff-ffff-ffff-ffffffffffff/resourceGroups/exampleresourcegroup/providers/Microsoft.DBForPostgreSql/servers/examplesource",
    target_db_server_name="exampletarget")
package main

import (
	dbforpostgresql "github.com/pulumi/pulumi-azure-native-sdk/dbforpostgresql/v3"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := dbforpostgresql.NewMigration(ctx, "migration", &dbforpostgresql.MigrationArgs{
			DbsToMigrate: pulumi.StringArray{
				pulumi.String("exampledatabase1"),
				pulumi.String("exampledatabase2"),
				pulumi.String("exampledatabase3"),
				pulumi.String("exampledatabase4"),
			},
			Location:             pulumi.String("westus"),
			MigrateRoles:         pulumi.String(dbforpostgresql.MigrateRolesEnumTrue),
			MigrationMode:        pulumi.String(dbforpostgresql.MigrationModeOffline),
			MigrationName:        pulumi.String("examplemigration"),
			OverwriteDbsInTarget: pulumi.String(dbforpostgresql.OverwriteDbsInTargetEnumTrue),
			ResourceGroupName:    pulumi.String("exampleresourcegroup"),
			SecretParameters: &dbforpostgresql.MigrationSecretParametersArgs{
				AdminCredentials: &dbforpostgresql.AdminCredentialsArgs{
					SourceServerPassword: pulumi.String("examplesourcepassword"),
					TargetServerPassword: pulumi.String("exampletargetpassword"),
				},
			},
			SourceDbServerResourceId: pulumi.String("/subscriptions/ffffffff-ffff-ffff-ffff-ffffffffffff/resourceGroups/exampleresourcegroup/providers/Microsoft.DBForPostgreSql/servers/examplesource"),
			TargetDbServerName:       pulumi.String("exampletarget"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;

return await Deployment.RunAsync(() => 
{
    var migration = new AzureNative.DBforPostgreSQL.Migration("migration", new()
    {
        DbsToMigrate = new[]
        {
            "exampledatabase1",
            "exampledatabase2",
            "exampledatabase3",
            "exampledatabase4",
        },
        Location = "westus",
        MigrateRoles = AzureNative.DBforPostgreSQL.MigrateRolesEnum.True,
        MigrationMode = AzureNative.DBforPostgreSQL.MigrationMode.Offline,
        MigrationName = "examplemigration",
        OverwriteDbsInTarget = AzureNative.DBforPostgreSQL.OverwriteDbsInTargetEnum.True,
        ResourceGroupName = "exampleresourcegroup",
        SecretParameters = new AzureNative.DBforPostgreSQL.Inputs.MigrationSecretParametersArgs
        {
            AdminCredentials = new AzureNative.DBforPostgreSQL.Inputs.AdminCredentialsArgs
            {
                SourceServerPassword = "examplesourcepassword",
                TargetServerPassword = "exampletargetpassword",
            },
        },
        SourceDbServerResourceId = "/subscriptions/ffffffff-ffff-ffff-ffff-ffffffffffff/resourceGroups/exampleresourcegroup/providers/Microsoft.DBForPostgreSql/servers/examplesource",
        TargetDbServerName = "exampletarget",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.dbforpostgresql.Migration;
import com.pulumi.azurenative.dbforpostgresql.MigrationArgs;
import com.pulumi.azurenative.dbforpostgresql.inputs.MigrationSecretParametersArgs;
import com.pulumi.azurenative.dbforpostgresql.inputs.AdminCredentialsArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var migration = new Migration("migration", MigrationArgs.builder()
            .dbsToMigrate(            
                "exampledatabase1",
                "exampledatabase2",
                "exampledatabase3",
                "exampledatabase4")
            .location("westus")
            .migrateRoles("True")
            .migrationMode("Offline")
            .migrationName("examplemigration")
            .overwriteDbsInTarget("True")
            .resourceGroupName("exampleresourcegroup")
            .secretParameters(MigrationSecretParametersArgs.builder()
                .adminCredentials(AdminCredentialsArgs.builder()
                    .sourceServerPassword("examplesourcepassword")
                    .targetServerPassword("exampletargetpassword")
                    .build())
                .build())
            .sourceDbServerResourceId("/subscriptions/ffffffff-ffff-ffff-ffff-ffffffffffff/resourceGroups/exampleresourcegroup/providers/Microsoft.DBForPostgreSql/servers/examplesource")
            .targetDbServerName("exampletarget")
            .build());

    }
}
resources:
  migration:
    type: azure-native:dbforpostgresql:Migration
    properties:
      dbsToMigrate:
        - exampledatabase1
        - exampledatabase2
        - exampledatabase3
        - exampledatabase4
      location: westus
      migrateRoles: True
      migrationMode: Offline
      migrationName: examplemigration
      overwriteDbsInTarget: True
      resourceGroupName: exampleresourcegroup
      secretParameters:
        adminCredentials:
          sourceServerPassword: examplesourcepassword
          targetServerPassword: exampletargetpassword
      sourceDbServerResourceId: /subscriptions/ffffffff-ffff-ffff-ffff-ffffffffffff/resourceGroups/exampleresourcegroup/providers/Microsoft.DBForPostgreSql/servers/examplesource
      targetDbServerName: exampletarget

Setting migrateRoles to “True” instructs the migration service to copy user accounts, roles, and their associated permissions from source to target. This ensures that application connection strings and access patterns continue working after migration without manual role recreation.

Beyond these examples

These snippets focus on specific migration-level features: validation-only and full migration modes, on-premises and cross-cloud source types, and private endpoint routing and role migration. They’re intentionally minimal rather than full migration workflows.

The examples require pre-existing infrastructure such as source PostgreSQL servers (Azure Single Server, on-premises, or other clouds), target Azure Database for PostgreSQL Flexible Server, migration instance flexible servers for private endpoint scenarios, and network connectivity between source and target. They focus on configuring the migration rather than provisioning the database infrastructure.

To keep things focused, common migration patterns are omitted, including:

  • Custom username configuration (sourceServerUsername, targetServerUsername)
  • Migration window scheduling (migrationWindowStartTimeInUtc, migrationWindowEndTimeInUtc)
  • Cutover triggering and database-specific cutover (triggerCutover, dbsToTriggerCutoverOn)
  • Migration cancellation (cancel, dbsToCancelMigrationOn)
  • Logical replication setup (setupLogicalReplicationOnSourceDbIfNeeded)
  • Custom FQDN overrides (sourceDbServerFullyQualifiedDomainName, targetDbServerFullyQualifiedDomainName)

These omissions are intentional: the goal is to illustrate how each migration feature is wired, not provide drop-in migration orchestration. See the Migration resource reference for all available configuration options.

Let's manage Azure Database for PostgreSQL Migrations

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Migration Configuration & Options
What's the difference between Validate and ValidateAndMigrate migration options?
migrationOption set to ‘Validate’ performs validation only without migrating data, while ‘ValidateAndMigrate’ validates and then performs the actual migration.
What source types are supported for PostgreSQL migration?
Supported source types include ApsaraDB_RDS, AWS, AWS_AURORA, AWS_EC2, AWS_RDS, AzureVM, Crunchy_PostgreSQL, Digital_Ocean_Droplets, Digital_Ocean_PostgreSQL, EDB, EDB_Oracle_Server, EDB_PostgreSQL, GCP, GCP_AlloyDB, GCP_CloudSQL, GCP_Compute, Heroku_PostgreSQL, Huawei_Compute, Huawei_RDS, OnPremises, PostgreSQLCosmosDB, PostgreSQLFlexibleServer, PostgreSQLSingleServer, and Supabase_PostgreSQL.
What migration modes are available?
The migrationMode property supports Online and Offline modes. All provided examples use Offline mode.
Source & Target Configuration
How do I format the source server connection string for different source types?
For sourceType of ‘PostgreSQLSingleServer’, use the full Azure resource ID. For other source types, use the format ‘ipaddress:port@username’ or ‘hostname:port@username’ (e.g., ’examplesource:5432@exampleuser’).
What are the default SSL modes for different source types?
The default sslMode is ‘VerifyFull’ for PostgreSQLSingleServer sources and ‘Prefer’ for all other source types.
How do I specify custom admin usernames for source and target servers?
Within secretParameters, use sourceServerUsername and targetServerUsername to specify custom usernames (e.g., ’newadmin@examplesource’ for source, ’targetadmin’ for target).
How do I configure a migration to use a private endpoint?
Set migrationInstanceResourceId to the resource ID of a flexible server that will serve as the private endpoint migration instance.
Database Selection & Control
Can I migrate only specific databases instead of all databases?
Yes, use the dbsToMigrate array to specify the names of databases you want to migrate (e.g., [’exampledatabase1’, ’exampledatabase2’]).
What happens if databases already exist on the target server?
If overwriteDbsInTarget is set to ‘False’, the migration workflow will pause and wait for manual confirmation when it detects existing databases. Set it to ‘True’ to allow automatic overwriting.
Can I migrate database roles and permissions along with the data?
Yes, set migrateRoles to ‘True’ to include roles and permissions in the migration.
Migration Lifecycle Operations
How do I trigger cutover for my migration?
Set triggerCutover to ‘True’ to trigger cutover for the entire migration. To trigger cutover for specific databases only, set triggerCutover to ‘True’ and specify database names in the dbsToTriggerCutoverOn array.
How do I cancel a migration in progress?
Set cancel to ‘True’ to cancel the entire migration. To cancel specific databases only, set cancel to ‘True’ and specify database names in the dbsToCancelMigrationOn array.
Resource Constraints
What properties can't be changed after creating a migration?
The following properties are immutable after creation: location, migrationName, resourceGroupName, subscriptionId, and targetDbServerName.

Using a different cloud?

Explore database guides for other cloud providers: