Build

Direct database connections

Point any Postgres tool at your app's database: db.atberth.com, port 5432, TLS, a login that only reaches your app. On Pro and up.

What it is

Every app is its own Postgres 17 database. On Pro, Agency and Business you can connect to it directly, with any tool that speaks Postgres: psql, TablePlus, DBeaver, Postico, Prisma, Drizzle, SQLAlchemy, Metabase, or Terraform's postgresql provider. Free apps use the SQL endpoint and the API instead.

The direct login has the same power as the app's secret key. Treat the connection string like that key: keep it on your machine or your server, never in a phone or browser app.

Turn it on and connect

berth db on --app "$APP"
# postgresql://app_demo_direct:…@db.atberth.com:5432/app_demo?sslmode=require
psql "postgresql://app_demo_direct:…@db.atberth.com:5432/app_demo?sslmode=require"
berth db psql --app "$APP"     # or let the CLI open psql for you (this makes a new password)

The password is shown once. Run berth db rotate to get a new one: the old one stops working and anyone connected with it is disconnected. berth db off removes the login. The same thing over HTTP, with the app's secret key:

curl -X POST   https://api.atberth.com/v1/apps/$APP/database/connection -H "apikey: $SECRET"   # on, or rotate
curl           https://api.atberth.com/v1/apps/$APP/database/connection -H "apikey: $SECRET"   # host, user, on or off
curl -X DELETE https://api.atberth.com/v1/apps/$APP/database/connection -H "apikey: $SECRET"   # off
SettingValue
Host and portdb.atberth.com:5432
Databaseapp_<your app>
Userapp_<your app>_direct
TLSrequired. The certificate is a public Let's Encrypt one, so sslmode=verify-full works too.
Connections5 at a time per app. Use a pool in your server.
Statement time2 minutes. An open transaction that sits idle for 1 minute is closed.

How it fits with the rest of Berth

  • You connect as the app's owner, so tables you create in psql show up in the API, the console and backups like any other.
  • Row policies apply to end users calling the API. A direct connection is a server-side login, like the secret key, and sees every row.
  • Leave the _berth schema alone. It holds your app's users, sessions and settings.
  • Writes made here skip the API's per-request row checks, so Berth checks the database size every hour. If the app is over its plan's size limit, or the server is short of disk, the login pauses (existing data stays and the API keeps working) and comes back on its own once that's fixed.
  • If the account goes back to Free, the direct login is removed within the hour.

Security

Only logins named *_direct may connect from outside, only over TLS, only with SCRAM passwords, and only to their own app's database. Postgres's own accounts and Berth's internal ones cannot log in from the internet at all. Passwords are 32 random bytes. An address that fails to log in 10 times in 10 minutes is blocked for an hour, and longer if it keeps trying.

Terraform

Manage tables, extensions, roles and grants inside your app's database with the community cyrilgdn/postgresql provider pointed at the direct connection. The app itself, keys and settings stay in the API and CLI.

terraform {
  required_providers {
    postgresql = { source = "cyrilgdn/postgresql", version = "~> 1.25" }
  }
}
variable "berth_db_password" { sensitive = true }
provider "postgresql" {
  host      = "db.atberth.com"
  port      = 5432
  database  = "app_demo"
  username  = "app_demo_direct"
  password  = var.berth_db_password
  sslmode   = "require"
  superuser = false
}
resource "postgresql_extension" "trgm" {
  name = "pg_trgm"
}
resource "postgresql_schema" "reporting" {
  name  = "reporting"
  owner = "app_demo"
}

For table definitions, most teams prefer a migration tool (Prisma Migrate, Drizzle Kit, Atlas, Flyway, sqitch) over Terraform. Any of them works with the same connection string.