Skip to main content

Postgres

Create managed PostgreSQL, connect with returned credentials, and plan storage, backups, recovery, and upgrades.

Share
Last updated on September 23, 2026
On this page

Bex manages PostgreSQL through CloudNativePG. A database is a separate resource from your application services: several applications can connect to it, and replacing an application does not replace the database.

Compute, storage, backup support, and high availability depend on the selected plan and configured infrastructure. A created resource is not yet a ready database, and configured backups are not proof of a completed recovery point.

Create a database

Use the dashboard's Postgres creation flow, or declare a database in a render.yaml Blueprint:

yaml
databases:
  - name: app-db
    plan: free
    postgresMajorVersion: "16"

Choose a supported plan and version for your application. The Blueprint field is postgresMajorVersion; the REST create field is version. Do not copy field names between these formats.

To create an explicitly private database through REST, set BEX_API_URL to your instance's API origin and BEX_TOKEN to an authorized workspace token:

bash
curl --fail-with-body -X POST "$BEX_API_URL/v1/postgres" \
  -H "Authorization: Bearer $BEX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"app-db","plan":"free","version":"16","public":false}'

Check the target workspace and resource plan before creating it. REST defaults public to true when omitted for Render-client compatibility; the shared core and Blueprint workflow default differently. Set access intentionally, and inspect the resulting resource rather than assuming every interface has the same default.

The resource id is stable. Its display name can change; PostgreSQL's database name and database user are separate identifiers chosen at creation and are immutable. Wait for the database to become available before connecting.

Retrieve connection details

Open the database's Connections panel, or set DATABASE_ID to its returned id:

bash
curl --fail-with-body "$BEX_API_URL/v1/postgres/$DATABASE_ID/connection-info" \
  -H "Authorization: Bearer $BEX_TOKEN"

This response contains credentials and requires permission to view sensitive values. Keep it out of source control, public logs, and shared transcripts.

ConnectionUse it for
internalConnectionStringApplications on an allowed Bex private-network path.
externalConnectionStringExternal clients when public access and the instance's database gateway are configured.
internalConnectionPoolString / externalConnectionPoolStringPgBouncer connections when the pooler and corresponding route are ready.

Do not assemble a hostname from the display name, assume a .default.svc namespace, or reuse another database's URL. External hostnames depend on the instance's configured database domain. Public access enabled without a working external host can cause connection-info to report that infrastructure is unavailable.

For an external connection, preserve the returned sslmode=verify-full and configure your PostgreSQL client's trust store for the issuing CA. Do not replace the hostname with an IP or weaken verification to resolve a certificate error. Internal URLs do not themselves promise TLS; follow the instance's internal transport policy rather than assuming private networking is encryption.

After securely setting DATABASE_URL to the appropriate returned URL, test a read-only query:

bash
psql "$DATABASE_URL" -c 'SELECT 1;'

Connect an application with a Blueprint reference

Let Bex supply the credential through an environment reference:

yaml
services:
  - name: api
    type: web
    runtime: docker
    repo: https://github.com/your-org/api
    envVars:
      - key: DATABASE_URL
        fromDatabase:
          name: app-db
          property: connectionString
databases:
  - name: app-db
    plan: free
    postgresMajorVersion: "16"

Replace the repository and validate the complete Blueprint. Your application reads DATABASE_URL; the password does not belong in the checked-in YAML. See Secrets and Private network.

Restrict access and manage capacity

External IP allowlists constrain the public gateway. Internal connections still require valid credentials and an allowed workspace/environment network path; they are not universally reachable from every Bex workload.

Storage grows but does not shrink. Plan changes and version changes can affect availability; check requested and actual capacity after reconciliation. Storage autoscaling is a separate database setting, not application replica scaling. Monitor storage usage, connections, and query behavior before choosing more compute or storage.

PgBouncer can reduce connection pressure when configured. Rehearse direct versus pooled clients before scaling with Postgres pooling before scaling. Read replicas can serve read-only workloads; their connection details are separate from the primary's. High availability provides a standby/failover configuration where supported. Neither a standby nor a replica replaces a backup against accidental deletes or bad migrations.

Back up and recover

Check the database's Recovery view before relying on point-in-time recovery. Through REST, the current recovery-info operation uses POST:

bash
curl --fail-with-body -X POST \
  "$BEX_API_URL/v1/postgres/$DATABASE_ID/recovery-info" \
  -H "Authorization: Bearer $BEX_TOKEN"

A backup-capable plan still needs configured backup storage, completed backups, and an established recovery window. Free databases do not provide the same recovery capability. If no usable window is reported, do not assume a selected time can be restored.

Recovery creates a new database from the source backup; it does not rewind the source in place. Choose a new name and a target time within the reported window. The API accepts these as name and targetTime at POST /v1/postgres/{id}/recover. Wait for recovery to finish, inspect the data, then deliberately update application connections. A successful request is not proof that recovery has completed.

Logical exports use POST /v1/postgres/{id}/export to request an export and GET /v1/postgres/{id}/export to inspect available results. Protect downloaded data and export URLs. Test restoration before depending on an export for a migration or disaster-recovery plan.

Self-hosted operators rehearsing platform/auth Postgres archives (not a tenant database recovered through this product API) should use the isolated drill in Recovery: Postgres and the shared Platform recovery preparation guide.

Upgrade or remove a database

Major-version upgrades use an offline upgrade path, so schedule an interruption, check extension/application compatibility, and verify a completed backup first. Bex gates upgrades on backup readiness for plans that require it. Do not treat an enabled-backup flag as a substitute for a completed backup.

Suspend and resume preserve the resource configuration; restart interrupts connections. Deletion removes the managed database and its storage. Export anything you need to retain before deletion, and check the exact resource id. See App lifecycle for the related operational concepts.

Troubleshoot

For failed connections, check readiness, the chosen internal/external path, network policy, credentials, and TLS trust. If connections exhaust the limit, inspect pool sizes across all application replicas. For recovery failures, inspect the available recovery window and backup status before retrying. Persistent application files belong on service disks, which have a different backup and recovery model.

Was this page helpful?

Run this on infrastructure you own

bex is the open-source, AI-native Render alternative — push a git repo and get a running HTTPS service on your own machines.

Get started with bex