Database Setup¶
The app uses a single PostgreSQL database. How it's provisioned differs by deployment type; how the app connects to it is the same underlying mechanism either way.
Environment variables¶
| Variable | Purpose | Native/PM2 | Docker |
|---|---|---|---|
DB_USER |
Postgres role name | Required | Required |
DB_PASSWORD |
Postgres role password (plaintext) | Set in .env, or encrypted — see below |
Set in .env |
DB_PASSWORD_ENC |
Encrypted password (replaces DB_PASSWORD once encryption is set up) |
Optional, recommended | Not used |
DB_NAME |
Database name | Required | Required |
DB_HOST |
Postgres host | Defaults to localhost |
N/A — compose sets DATABASE_URL directly with host db |
DB_PORT |
Postgres port | Defaults to 5432 |
N/A |
DATABASE_URL |
Full connection string | Not set directly — built at startup from the parts above | Set directly by docker-compose.prod.yml as a container env var |
How the connection string is built¶
For native/PM2 installs, the backend never stores DATABASE_URL as a literal .env value. Instead, buildDatabaseUrlFromParts() in backend/src/common/config/env-secrets.ts assembles it at process startup from DB_USER, DB_PASSWORD (or its decrypted DB_PASSWORD_ENC), DB_NAME, DB_HOST, and DB_PORT. This is deliberate: it keeps the password in exactly one place in .env rather than duplicated — once plain in DB_PASSWORD and again embedded inside a DATABASE_URL string.
Docker Compose is the one exception. docker-compose.prod.yml sets DATABASE_URL directly as a container env var for the backend service (pointing at the db container by its internal hostname), and the app's startup loader respects an already-set DATABASE_URL and does nothing further.
Provisioning¶
install-onprem.sh creates the Postgres role and database for you on first install, using DB_USER/DB_PASSWORD/DB_NAME from .env. On subsequent runs (upgrades), it reconciles the Postgres role's password to match whatever .env currently holds — see Changing the Database Password for why that matters if you rotate the password by hand.
The db service is a stock postgres:15-alpine container. POSTGRES_USER/POSTGRES_PASSWORD/POSTGRES_DB from .env only take effect the first time the container initializes an empty postgres_prod_data volume — editing .env afterwards does not change the already-initialized database's password. See Changing the Database Password.
Next steps¶
- Secrets & Encryption — don't leave
DB_PASSWORDin plaintext on a native/PM2 install - Changing the Database Password