Render Tutorials
Postgres on Render: a deep dive

Provisioning and the immutable fields

⏱ 7 min

There are two ways to provision Render Postgres: the Render Dashboard and a Blueprint. Both end at the same place - a running instance with a connection string. The difference is repeatability.

This step covers both flows and the fields you absolutely have to get right the first time.

The Render Dashboard: best for one-offs and exploration

flowchart LR
  dash["Dashboard:<br/>+ New → Postgres"]
  fields["Pick name, region,<br/>plan, version, storage"]
  click["Click Create Database"]
  ready["Provisioned in<br/>~1 min, URLs live"]

  dash --> fields --> click --> ready

Use the Render Dashboard when:

  • You’re prototyping and you might delete the database in an hour.
  • You want to poke at settings interactively before committing them to YAML.
  • The database is a one-off (e.g. a temporary analytics DB for a one-time report).

The Render Dashboard creates exactly one instance. There’s no rollback if you mistype the name - you’d delete and re-create.

Blueprint: best for anything you’ll run for more than a week

render.yaml
databases:
- name: app-db
plan: basic-256mb
region: oregon
postgresMajorVersion: "16"
databaseName: appdata
user: appuser
diskSizeGB: 5

A Blueprint declares the database alongside the services that consume it. The whole topology lives in one file, the file lives in Git, and render blueprints validate checks it before you sync.

Use a Blueprint when:

  • You’ll have more than one environment (production + staging).
  • You want a teammate to spin up an identical copy with one PR.
  • You want infrastructure-as-code-style review on database changes.

For the validation loop and IDE setup, see the advanced Blueprint patterns intro. Everything in this step works with both a Blueprint-managed database and a Render Dashboard-managed one.

The fields you cannot change later

This is the part most worth slowing down on. Five fields are immutable after the instance is created. You cannot edit them in the Render Dashboard or the Blueprint after the database exists.

FieldWhy it’s locked
name (Blueprint resource id)The identifier fromDatabase references - renaming would orphan every consumer
databaseNameThe actual database name in the connection URL path
userThe Postgres role used by the connection string
regionPostgres data lives on regional storage; moving = a new instance
postgresMajorVersionMajor upgrades are not in-place edits
flowchart LR
  create["Create database"]
  immutable["name<br/>databaseName<br/>user<br/>region<br/>postgresMajorVersion"]
  changeable["plan<br/>diskSizeGB (only up)<br/>HA on/off (per plan)<br/>read replicas<br/>display name"]

  create --> immutable
  create --> changeable
  immutable -.->|"never"| edit1["Edit"]
  changeable -->|"yes, in the Render Dashboard or a Blueprint"| edit2["Edit"]

The Render Dashboard display name - what you see in the sidebar - can be renamed. That’s distinct from the Blueprint resource name (the id used by fromDatabase) and from databaseName (the actual database). All three sound similar; only one is mutable.

A safe creation checklist

Before you click Create or git push:

  1. Region matches your services Same region as the services that will hit DATABASE_URL. Cross-region adds tens of ms per query.
  2. `postgresMajorVersion` is the latest supported Or whatever your team standardizes on. Major upgrades later require a new instance and a migration.
  3. `databaseName` is what your migrations expect Most ORMs default to postgres or your app name. Match what your migration tooling will look for.
  4. `user` is something you can remember It shows up in pg_stat_activity queries forever. appuser or your app slug is fine.
  5. `plan` is the right starting point You can resize plan later (with brief downtime). Start small if unsure - moving up is easier than the other way.
  6. `diskSizeGB` covers next 6 months 1 GB or multiples of 5 GB. You can grow it; you can never shrink it. Start conservatively.

Storage: 1 GB or multiples of 5 GB

The valid initial sizes are 1 GB (the minimum) or multiples of 5 GB: 5, 10, 15, 20, and so on, up to the plan’s maximum. Pick a size that covers your expected next 3 to 6 months of growth - autoscaling kicks in when you fill up (covered in step 05) but it has cooldowns and is one-way.

render.yaml - sizing examples
databases:
- name: small-app-db
plan: basic-256mb
diskSizeGB: 1 # the minimum
- name: typical-app-db
plan: basic-1gb
diskSizeGB: 10 # ~3-6 months for a typical SaaS
- name: heavier-app-db
plan: pro-4gb
diskSizeGB: 50

If you’re not sure, pick 1 GB and let autoscaling take care of growth. You’ll only pay for what you have, and the extra steps from autoscaling are background events you’ll never notice in normal operation.

What if I picked the wrong immutable field?

There’s no in-place edit, but there’s a clean recovery path: restore a snapshot to a new instance with the right settings.

  1. Provision a new database with the corrected settings New region, new postgresMajorVersion, new user, whatever you got wrong. Different name so the old one isn’t disturbed.
  2. Take a snapshot of the old database Either the most recent automatic snapshot, or pg_dump for portability.
  3. Restore the snapshot to the new instance Either via the Render Dashboard’s Restore flow or pg_restore for -Fc dumps.
  4. Cut over consumers Update fromDatabase references in your Blueprint to point at the new database name. Sync. Services pick up the new DATABASE_URL on next deploy.
  5. Delete the old database Once you’ve verified the new one works for at least a deploy or two, remove the old database from the Blueprint and delete it.

The whole thing is a couple of hours plus however long the restore takes - annoying, not catastrophic. The cleanup steps for backups and pg_dump are covered in step 08.

You created `app-db` six months ago in the `oregon` region with `postgresMajorVersion: 15`. Now you want to move it to `frankfurt` and upgrade to `postgresMajorVersion: 16`. What's the migration path?

What you learned

  • Two creation paths: the Render Dashboard for one-offs, Blueprint (`databases:` block) for anything you'll keep
  • Five immutable fields after creation: `name`, `databaseName`, `user`, `region`, and `postgresMajorVersion`
  • Storage: `1 GB` minimum or multiples of `5 GB`. You can grow it later, but never shrink it
  • Plan, disk size (up only), HA, read replicas, and display name are all mutable - adjust them later as you learn how the workload behaves
  • When you need to change an immutable field: create a new instance, restore a snapshot or `pg_dump` into it, repoint consumers, delete the old one