AZURE POSTGRESQL → STACKIT POSTGRESQL FLEX · TUTORIAL
Azure PostgreSQL flexible server to STACKIT PostgreSQL Flex
A flexible server becomes one STACKIT PostgreSQL Flex instance. StackToIT writes the instance with a flavor, storage, a daily backup, retention and an access list taken from your firewall rules. It names what it does not carry: the administrator login, the database, the zones and, in the architect report, the server parameters. This tutorial walks one demo estate from input to restore.
From the Azure server to the STACKIT instance
A demo estate written for this page and assessed by StackToIT on 4 November 2026: a General Purpose server, version 15, zone-redundant high availability, private access only. Left: two blocks of the input (the database and the server parameter blocks are omitted here). Right: the resource block of the STACKIT Terraform the engine wrote; the review comments above the block in the file are left out here. The input blocks are not adjacent in main.tf, so each has its own pane, verbatim.
resource "azurerm_postgresql_flexible_server" "billing" {
name = "psql-billing-gwc"
resource_group_name = azurerm_resource_group.data.name
location = azurerm_resource_group.data.location
version = "15"
sku_name = "GP_Standard_D4s_v3"
storage_mb = 131072
administrator_login = "billingadmin"
administrator_password = var.pg_admin_password
backup_retention_days = 14
geo_redundant_backup_enabled = false
public_network_access_enabled = false
zone = "1"
high_availability {
mode = "ZoneRedundant"
standby_availability_zone = "2"
}
}resource "azurerm_postgresql_flexible_server_firewall_rule" "office" {
name = "office"
server_id = azurerm_postgresql_flexible_server.billing.id
start_ip_address = "203.0.113.10"
end_ip_address = "203.0.113.20"
}resource "stackit_postgresflex_instance" "billing" {
project_id = var.project_id
name = "psql-billing-gwc"
version = "15"
flavor_id = "4.32-replica"
storage = {
class = var.postgresflex_storage_class
size = 128
}
backup_schedule = "0 2 * * *"
network = {
acl = var.billing_allowed_cidrs
}
retention_days = 32
}The flavor covers the source size
The source SKU GP_Standard_D4s_v3 has 4 vCPU and 16 GiB. The run picks 4.32-replica, the smallest highly available flavor in the eu01 catalogue that covers it: 4 vCPU and 32 GiB. High availability becomes a replica flavor, which the run describes as three nodes that mirror each other. It does not claim where each node runs or how a failover behaves.
Backups on the STACKIT scale
Azure keeps 14 days; the provider accepts 32 to 90, so retention_days becomes 32. The run sets 02:00 daily as a default schedule, and STACKIT documents daily backups only. Point-in-time restore on PostgreSQL Flex creates a new cloned instance.
Version and storage carry over
The run reports that version 15 is one PostgreSQL Flex offers, from 14 to 18. The 131072 MB of storage becomes size 128; the storage class is a variable without a default, so you choose it.
Firewall rules become the ACL
The range 203.0.113.10 to 203.0.113.20 is converted into four CIDRs in the default of the ACL variable, so the list is yours to confirm.
What the draft says it did not carry
Verbatim lines from the comments in terraform/data.tf. They are the work that remains after the instance exists.
# NOT CARRIED (azurerm_postgresql_flexible_server.billing): administrator_login = billingadmin, administrator_password — the administrator login is not generated: create the users with stackit_postgresflex_user (pinned provider).
# NOT CARRIED (azurerm_postgresql_flexible_server.billing): public_network_access_enabled = false — the public-network access switch has no counterpart: clients reach the STACKIT instance through its ACL (network.acl) either way.
# NOT CARRIED (azurerm_postgresql_flexible_server.billing): zone = 1, high_availability.standby_availability_zone = 2 — the availability zone and the high-availability standby zone are not generated (pinned provider).
# NOT CARRIED (azurerm_postgresql_flexible_server_database.invoices): name = invoices, charset = UTF8, collation = en_US.utf8 — create the database with stackit_postgresflex_database (pinned provider) and restore its data.
# LEDGER backup retention: 14 days → retention_days = 32 — TRANSFORMED
# LEDGER network exposure: private → instance endpoint restricted by ACL — REVIEW
# LEDGER high availability: standby / multi-node → flavor_id = "4.32-replica" (a replica flavor: three nodes that mirror each other; no STACKIT page states the zone of each node or how a failover works, so a zone failure or an automatic takeover is not claimed) — TRANSFORMEDvariable "billing_allowed_cidrs" {
type = list(string)
description = "CIDRs allowed to reach azurerm_postgresql_flexible_server.billing. Default: the address ranges of the source server's firewall rules, as CIDRs."
default = ["203.0.113.10/31", "203.0.113.12/30", "203.0.113.16/30", "203.0.113.20/32"]
}Users and databases are yours to declare
The administrator login is not generated, and neither is the database. The comments name stackit_postgresflex_user and stackit_postgresflex_database as the resources to use.
Private becomes ACL-restricted
A STACKIT instance has its own hostname and IPv4 address and is reachable by default from predefined STACKIT address ranges; the ACL adds yours. A private scope exists as an opt-in for enabled accounts and may still change, so the exposure of a private Azure server changes unless you obtain it.
Server parameters need a manual look
The demo sets log_min_duration_statement to 500. The draft carries no line for it; it appears only in the architect report as an open critical setting, so list your server parameters and check each by hand.
How the settings map in this run
| Azure setting | STACKIT draft | Who acts |
|---|---|---|
| version = 15 | version = 15 | Confirm the engine version against the catalogue |
| sku_name GP_Standard_D4s_v3 | flavor_id 4.32-replica | Data Architect confirms size and node count |
| storage_mb 131072 | storage size 128, class from a variable | Choose the storage class |
| backup_retention_days 14 | retention_days 32, schedule 0 2 * * * | Accept the new retention |
| geo_redundant_backup_enabled false | Not generated; open setting | Data Architect confirms the backup location matches |
| public_network_access_enabled false | network.acl from the variable | Network Architect decides the scope |
| Firewall rule office | Four CIDRs in the ACL default | Confirm the ranges |
| administrator_login, database invoices | Not generated | Declare users and database |
Classes as the run decided them: REPLATFORM with MEDIUM confidence for the server. The database, the rule and the parameter are part of the server unit.
The steps in order
Assess the Terraform
Run stacktoit assess on the folder with the azurerm code and read the open requests it lists. The demo has one variable without a value, the administrator password; the run reports it and says it stops nothing.
Work through the four packages
The run groups the open settings in four work packages with an owner each: Data, Identity, Network and Platform Architect. They hold the backup location, the resource-group scope and administrator login, the exposure and the firewall ranges, and the standby zone and names.
Add users and the database
Declare the users and the database as described in the next section, with the owner set to a declared user. The provider generates each user's password and marks it sensitive.
Dump and restore
Azure documents pg_dump and pg_restore for this, with the directory format for parallel work. pg_dump handles one database at a time and does not dump roles. Create the roles as users on the new instance rather than replaying a role dump, and check the grants afterwards.
Point clients at the new host
Connection strings use the instance hostname and port 5432, and STACKIT advises checking the ACL when a connection times out. The run adds that PostgreSQL Flex always encrypts connections with TLS 1.3, so clients must support it and trust the new server certificate.
Users, database and the move, by hand
Users first
Declare one stackit_postgresflex_user per application login with project_id, instance_id, username and roles; the provider's own example uses the role login. The password is a read-only, sensitive attribute the provider fills, so it ends up in the state.
Then the database
stackit_postgresflex_database takes a name and an owner, which is the username of a declared user. In the demo that is the database invoices, owned by the application user.
Dump in the directory format
Azure documents pg_dump -Fd -j with a number of cores for larger databases, and pg_restore -Fd -j -d into the target database, with errors written to errors.log and checked afterwards. This is practice for you to run; StackToIT runs neither command.
Client versions matter
Azure states that the tools must be the same or a newer major version than the servers you export from and import into. With version 15 on both sides, version 15 tools or newer qualify.
Roles without passwords
On a flexible server, pg_dumpall -r needs --no-role-passwords, because the role passwords cannot be read there. A role dump therefore carries no passwords; the STACKIT users get the passwords the provider generates.
Restores create a new instance
STACKIT restores a backup or a point in time by cloning it into a new instance in the same project. Plan that a restore changes the hostname clients connect to.
Questions database teams ask
Does geo-redundant backup carry over?
The draft sets no backup location, and the provider has no attribute for it. The run leaves the setting open and asks a person to confirm that the STACKIT backups, which stay in the region, are enough.
Can we restore a dump with roles from Azure?
Azure documents dumping roles with pg_dumpall and the option --no-role-passwords on flexible servers. On STACKIT, create users with the provider resource and set grants yourself; do not assume a replayed role dump works.
How much downtime does dump and restore need?
It depends on the data size and change rate, which the source does not state. The run says so in its data movement notes, quotes only the provisioned 131072 MB, which is not the data size, and leaves the method to you.
Is the instance reachable like the private Azure server?
Not by default. It is reachable from the ranges in the ACL and from predefined STACKIT ranges. Decide the ACL, and ask whether you need the private scope, before any apply.
Sources
Your next move: STACKIT.
Tell us about your estate. We show you what StackToIT delivers for it: target architecture, Terraform artifacts and a structured migration plan.