Skip to main content
Qovery creates it in the AWS account of the environment’s cluster, as a Blueprint service in one of your environments.
New to this? You don’t need to know Kubernetes or Terraform. Qovery sets up Amazon RDS for PostgreSQL in your cloud account and manages it for you: you fill in a form, or paste the prompt below into your coding agent. The values it publishes, listed under Outputs, reach your other services as environment variables. Qovery tells you when a newer version of the Blueprint is available. Check the requirements in the Reference section before you start, and try it first in a development environment.

Create it

  1. Open the environment, then New service › Blueprint.
  2. Find Amazon RDS for PostgreSQL in the catalog and pick the major version.
  3. Fill in the variables. Required ones are marked; the others use their defaults.
  4. Create the service, and deploy it now or later.
You don’t add any file to your repository. Qovery creates the Blueprint from the Console or the API.

Variables and outputs

Generated from qbm.yml at AWS/postgres/18/1.8.0, the manifest the Console form is built from.
Outputs become environment variables that other services in the environment can use. By default Qovery also creates an alias for each output, prefixed with the Blueprint’s name; see Aliases Qovery creates for outputs for the naming rules and the cases where no alias is created.
Secret variables and outputs are encrypted and masked in Qovery, but Terraform can also keep their values, and values derived from them, in its state. With the Qovery-managed state backend (the default), Qovery stores the state. If you use your own backend, protect it and keep state files out of version control.

Reference

From the Blueprint’s README. Creates an AWS RDS PostgreSQL 18 instance with configurable instance class, storage, backups, maintenance window, monitoring, and network settings. Storage is encrypted by default. When the blueprint creates the instance, the RDS identifier is derived from db_name: lowercased, each run of underscores turned into one hyphen, and a trailing hyphen dropped (AWS requirement). An adopted instance keeps its existing identifier (import_identifier), which can differ from db_name. The actual PostgreSQL database name is kept as provided.

Variables

Required

Available instance classes: every RDS instance class Qovery offers for native managed PostgreSQL and MySQL — the db.t3, db.t4g, db.m5–db.m8g, db.r5–db.r8g (including db.r5b), db.x2g, db.x2idn and db.x2iedn families, with their Graviton (g), Intel (i), local-storage (d) and network-optimized (n) variants. db.c6gd is left out because RDS offers it only for Multi-AZ DB clusters. The full list is in qbm.yml.

Credentials

Both are optional — omit them and Qovery supplies the values, the way native managed databases did. In the console, leaving the field blank omits it. Through the API or Terraform, omit the variable rather than sending an empty string: the platform rejects an empty variable value. Changing db_password rotates the live instance’s master password: the value is sent as a write-only argument, triggered by a version derived from the password itself, so a change reaches RDS and an unchanged password sends nothing. An adopted instance does not take part until manage_db_password is set to true. That keeps its import plan clean, and it has a consequence worth stating plainly: while the flag is false, editing db_password changes what the blueprint publishes without changing anything on the instance. Consumers pick up a credential RDS will reject. On an adopted instance, either set the flag before touching the password, or do not touch the password at all. Setting the flag is itself a write. Until then the version that triggers the send is null in state, so switching it to true moves that value and applies db_password to the instance — harmless when the two already agree, and an overwrite of the live password when they do not. Confirm the stored password is the one the instance actually has before opting in. A rotation also obeys apply_changes_now. Left false, RDS defers the password change to the maintenance window while the new value is published immediately — consumers redeployed in between cannot connect. Set apply_changes_now when you rotate. Adoption (import_identifier set) requires both explicitly. username is ForceNew on aws_db_instance, so a defaulted value would plan a replacement and destroy the live database; and RDS never returns the master password, so a generated one would be published as the credential without ever being applied.

Instance & storage

Storage autoscaling. With max_allocated_storage set, RDS grows the disk on its own when free space stays at or below 10% for 5 minutes, up to that ceiling. It waits until the previous storage change has finished optimizing, and grows a disk at most four times in 24 hours. Left empty, the blueprint keeps whatever the instance has, including a ceiling set in the AWS console.
  • The ceiling must be at least 10% above the current disk, not only above allocated_storage, and on each read replica above that replica’s own disk. Once autoscaling has grown a disk, the deploy fails before changing anything if the ceiling is too close to it, and names the minimum. An unchanged ceiling is not checked, except when allocated_storage raises the disk or a new replica is about to be created with it. A replacement that keeps the identifier is not caught: if its disk sits within 10% of the ceiling, AWS refuses it at apply, so raise the ceiling first.
  • It applies immediately, without a reboot, whatever apply_changes_now says: RDS ignores the apply-immediately flag for a ceiling change.
  • A disk never shrinks. The blueprint asks for the larger of allocated_storage and the live disk size, so a grown disk does not show as a change, and setting 0 after a growth turns autoscaling off at the current size.
  • With io1/io2 storage, AWS also requires the IOPS-to-ceiling ratio to stay within a range, and rejects a ceiling outside it when the deploy applies.

Network

By default the instance is attached to the Qovery cluster network: the DB subnet group created at cluster bootstrap (named after the cluster VPC id) and the cluster workers security group, so pods in the cluster can reach the database out of the box. On clusters deployed into an existing VPC (user-provided network), the ClusterId tag lookup may not resolve; set db_subnet_group_name and security_group_ids explicitly in that case.

Read replicas

Read replicas are asynchronous read-only copies of the primary — point analytics/BI tools (Metabase, Superset, dashboards, ad-hoc reporting) at their endpoints to keep heavy read traffic off the primary. They inherit the primary’s engine version, storage size, storage type, and encryption, and share its database name, master username, and password; connect with the same credentials at the replica endpoint. max_allocated_storage and cloudwatch_logs_export_enabled apply to every replica too: left unset, an existing replica keeps its own autoscaling ceiling and log exports, and a new one starts from the primary’s. Because replication is asynchronous, replicas are eventually consistent (fine for analytics, not for read-after-write). Creating replicas requires automated backups on the primary (backup_retention_period > 0, the default). Replica endpoints are exposed via the read_replica_endpoints output. Analytics tools running inside the cluster can reach them over the cluster network out of the box; set read_replica_publicly_accessible = true only for tools that live outside the VPC. To let such a tool in without opening the primary, set read_replica_publicly_accessible = true and list its egress IPs in read_replica_allowed_cidrs (e.g. the Metabase Cloud IPs for your region): the blueprint creates a dedicated security group allowing those CIDRs plus the VPC’s own CIDRs on the database port, and attaches it to the replicas instead of the primary’s groups. Replacing rather than adding is deliberate: on a Qovery-managed network the cluster workers group also carries the cluster-wide database.postgresql.allowed_cidrs rule (0.0.0.0/0 by default), which would otherwise leave a public replica reachable from anywhere. Clients inside the VPC keep access through the VPC CIDR rule. With the variable unset, replicas carry the primary’s security groups, including on an adopted instance.

Maintenance & upgrades

Backups

Deleting the service keeps a final snapshot and the automated backups by default, and both keep costing storage until deleted by hand: the snapshot indefinitely, the backups for backup_retention_period days. For a throwaway or test instance, set both skip_final_snapshot and delete_automated_backups to true. The final snapshot is named <cluster name>-<db name>-<YYYYMMDDhhmmss>: db_name slugged as for the identifier, the UTC time the name was stamped. The cluster name is cleaned in this order: any character AWS rejects is removed, hyphen runs are collapsed, it is cut to 160 characters to stay within the 255-character limit, then leading and trailing hyphens are dropped. The whole name is prefixed snap- if it does not start with a letter. It is stamped once at creation, so successive create/destroy cycles of the same name do not collide.

Monitoring

CloudWatch log export. cloudwatch_logs_export_enabled = true adds the postgresql log to what the instance already exports; RDS publishes it to the log group /aws/rds/instance/<identifier>/postgresql. false does not remove anything: the instance keeps the exports it has, so an export set in the AWS console (upgrade, for instance) survives every deploy.
  • To stop the export, disable it in the AWS console and keep the input false. With true, the next deploy turns it back on.
  • The log group is not managed by the blueprint. RDS creates it; the blueprint neither sets its retention (CloudWatch defaults to never expire) nor deletes it with the instance.
  • What gets logged follows the parameter group. The RDS default logs errors, failed logins and deadlocks; set log_min_duration_statement or auto_explain through db_parameters for more.

Misc

Parameters

Each value is either the parameter value, or an object carrying apply_method too. RDS applies a dynamic parameter with immediate (the default here) and refuses it for a static one, which needs pending-reboot:
  • Write values the way RDS stores them — plain integers in the parameter’s own unit (max_wal_size in MB, checkpoint_timeout in seconds). Anything else is normalised by AWS and shows up as a change on every deploy. JSON true/false are sent as 1/0.
  • Overriding shared_preload_libraries replaces the RDS default, pg_stat_statements. Keep it in the list, or Performance Insights’ SQL statistics stop.
  • The blueprint never reboots the instance to apply parameters. A new instance starts on the group. On an existing one, attaching the group for the first time, and every change to a pending-reboot parameter, waits for a reboot: the instance shows pending-reboot in the AWS console until you reboot it there. Changes to dynamic parameters apply without one.
  • The group is named <identifier>-params-<suffix> and its family follows the engine major (postgres18). With db_parameters set, a major upgrade creates a group of the new family with the same parameters and moves the instance onto it along with the engine. RDS upgrades the read replicas as part of the primary’s upgrade, so they move onto the new group in the same deploy, and only then is the old group deleted: it is never sent a parameter its version may not know.
  • A major upgrade with db_parameters set, or being cleared, needs apply_changes_now = true, and the deploy fails before changing anything otherwise. Deferred to the maintenance window, the upgrade would keep the old group attached, and it could not be deleted. Either apply the upgrade now, or upgrade first and set db_parameters afterwards.
  • Clearing db_parameters moves the instance and replicas back to default.postgres18 and deletes the group; dynamic parameters revert straight away, static ones at the next reboot. Left unset, the blueprint does not touch the parameter group, so a group attached by other means stays in place. The blueprint recognises its own group by name, <identifier>-params- followed by 26 hex characters: do not give a group of your own a name of that shape.

Outputs

Upgrading from an earlier blueprint version

Read this before repointing a deployment at this version.
  • Repointing a service from an older PostgreSQL major upgrades its engine in place. Qovery sets engine_version to the highest 18.x that RDS lists as a valid upgrade target from the running version, and Terraform runs the major upgrade (downtime; with apply_changes_now = false, in the next maintenance window). An instance already upgraded through RDS to 18 is only relabelled. An instance on a custom parameter group needs a group of the new family first: RDS refuses the upgrade otherwise. From a newer major, do not repoint here: RDS cannot downgrade.
  • Deleting now keeps a final snapshot and the automated backups for services created on this version. An existing service does not change behaviour: Qovery stores every variable default when the service is created, so repointing it here keeps skip_final_snapshot = true and delete_automated_backups = true. To keep a snapshot and backups on delete, set both to false on the service. The upgrade itself adds time_static.created and, with those set to false, updates skip_final_snapshot, delete_automated_backups and final_snapshot_identifier in place — Terraform-only arguments, nothing is sent to AWS and the instance is not rebooted.
  • For an instance this blueprint created, and for an adopted instance already opted in with manage_db_password, the first apply writes the master password once. Old state carries no record of what was last sent, so the value Qovery holds is applied. An instance whose password was rotated outside Terraform — which earlier versions of this document told you to do — is reset to the Qovery-held value, and applications using the out-of-band password stop connecting. Make the two agree before you upgrade. An adopted instance left at manage_db_password = false is not touched: nothing is sent, and an out-of-band rotation survives.
  • manage_db_password is one-way. Setting it back to false after an adopted instance has been handed over leaves Terraform with a change AWS rejects as “no modifications were requested”.
  • Terraform moves from 1.9.7 to 1.13.3, and 1.9.7 is no longer an accepted override. State written by 1.13.3 cannot be read by 1.9.7, so a deployment cannot be repointed at an earlier blueprint version once it has applied.
  • parameter_group_name is no longer ignored. Left unset (db_parameters empty), nothing changes: Terraform sends no value and a group attached in the AWS console stays. Setting db_parameters replaces that group with the blueprint’s, so copy any parameters you still need into it first.
  • On an adopted instance with read replicas, the replicas are now given the primary’s security groups explicitly, even with read_replica_allowed_cidrs unset. If they currently carry other groups (typically the VPC default group), the first apply swaps them in place: no replacement, no reboot. An instance this blueprint created is unaffected; its replicas already had these groups.
  • max_allocated_storage and enabled_cloudwatch_logs_exports are no longer ignored, and nothing changes until you set the new inputs: repointing leaves max_allocated_storage empty and cloudwatch_logs_export_enabled false, and both keep what the primary and each replica have, including autoscaling and exports set in the AWS console. allocated_storage now follows the live disk when that is larger, so a disk grown by autoscaling no longer shows as a change. Qovery can turn the log export on but not off; disable it in the AWS console.

Lifecycle ignore_changes

On the primary instance, engine_version is no longer ignored. Terraform requests the exact version held in the internal engine_version variable, which Qovery sets on every deploy:
  • the live version, while the service stays on this major
  • the highest valid upgrade target, when the service moves here from an older major.
With auto_minor_version_upgrade enabled, AWS may still move the running minor forward; the next deploy then requests that newer version, so Terraform never tries to go back. Read replicas inherit the primary’s version. A bare major such as "18" is never sent to a live instance, because AWS resolves it to the region’s default minor, which upgrades an older minor and is refused on a newer one. Without the variable, an existing instance keeps its live version (read through the aws_db_instance data source) and only a new instance gets the bare major. enabled_cloudwatch_logs_exports and max_allocated_storage are managed, on the primary and on the read replicas, but an unset input keeps the live value instead of clearing it: the blueprint reads each instance through the aws_db_instance data source on every plan, so an empty max_allocated_storage keeps the live ceiling and cloudwatch_logs_export_enabled = false keeps the live exports. A replacement that changes the identifier (a db_name change on an instance this blueprint created) finds no live instance and starts from the inputs alone. One that keeps it (an adopted instance, whose identifier is import_identifier, or a storage_encrypted toggle) reads the old instance, so the new one inherits its disk size, autoscaling ceiling and log exports. Two attributes remain ignored on the primary:
  • password — the master password moved to the write-only password_wo; ignoring the plain attribute stops the value left in older state reading as a removal.
  • tags — ignored on the primary and every read replica, so tag changes from the blueprint never reach an existing database. The reason is adoption: the native path tags managed RDS with cluster_id, which the YACE CloudWatch exporter filters DB metrics on.

Required AWS IAM permissions

The credentials used to deploy this blueprint must allow the actions below. The RDS actions target instances in any region you deploy to; EC2 read actions are needed so Terraform can look up the default VPC, subnets, and security groups when none are explicitly configured. The EC2 write actions are used while read_replica_allowed_cidrs is set, and on the apply that clears it (Terraform revokes the rules and deletes the group), so keep them until that apply has run.
When monitoring_interval > 0, the supplied monitoring_role_arn must be assumable by RDS (monitoring.rds.amazonaws.com trust relationship) and grant the AmazonRDSEnhancedMonitoringRole managed policy.