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:
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:
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:
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.
| Connection | Use it for |
|---|---|
internalConnectionString | Applications on an allowed Bex private-network path. |
externalConnectionString | External clients when public access and the instance's database gateway are configured. |
internalConnectionPoolString / externalConnectionPoolString | PgBouncer 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:
psql "$DATABASE_URL" -c 'SELECT 1;'Connect an application with a Blueprint reference
Let Bex supply the credential through an environment reference:
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:
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.