Skip to content

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