Secrets and Configs in Compose

An environment variable is visible to every process in the container, shows in docker inspect and leaks into logs. A Compose 514 secret is a file mounted read-only at /run/secrets/<name> in the services that list it, taken from a host file (file:) or a variable of the Compose process (environment:). postgres reads POSTGRES_PASSWORD_FILE (Environment Variables); BookNest's db/index.js gains the same convention:

db/index.js: reading the password from a file when one is givenJavaScript
// A *_FILE variable (a Compose or Kubernetes secret mounted as a file) wins over PGPASSWORD.
const password = process.env.PGPASSWORD_FILE
  ? fs.readFileSync(process.env.PGPASSWORD_FILE, 'utf8').trim()
  : process.env.PGPASSWORD || 'booknest';

The Pool now takes password. Generate a password, keep it out of Git 1,932 , and run production under its own project name so its volume never mixes with development data:

Running the production stack with a file secretShell
docker compose down >/dev/null 2>&1
mkdir -p secrets && openssl rand -base64 18 > secrets/db_password.txt
chmod 600 secrets/db_password.txt && echo 'secrets/' >> .gitignore
P="-p l3-booknest-prod -f compose.yaml -f compose.prod.yaml"
docker compose $P up -d --build --wait 2>&1 | grep Healthy | sort -u
docker compose $P exec api ls -ln /run/secrets | tail -1
docker compose $P exec api env | grep PGPASS
curl -s localhost:33000/api/books/3 | cut -c1-60; echo
Output
 Container l3-booknest-prod-api-1 Healthy
 Container l3-booknest-prod-db-1 Healthy
-rw------- 1 1000 1000 25 Sep 25 11:04 db_password
PGPASSWORD_FILE=/run/secrets/db_password
{"id":3,"title":"Salt and Saffron","author":"Priya Nair","ge

The API's environment holds only a path. Outside Swarm 514 a secret is a read-only bind mount, so the container sees the host file's owner and mode, here UID 1000 and 600: readable by the API (UID 1000) and by the postgres entrypoint (root). Configs do the same for non-secret files, from a file:, a variable or inline content:, mounted at /<name> or a target:. With plain Compose, protecting the host file is your job; Kubernetes 5,150 (Kubernetes) mounts its Secrets as files the same way.