Docker cookbook · Beginner
Run PostgreSQL in Compose with a healthcheck and persistent data
Start a database for development that keeps data and that the app waits for.
Approach
Use the official image with a named volume, a pg_isready healthcheck, credentials from a git-ignored
.env file, and depends_on: condition: service_healthy for the app.
Solution
services:
db:
image: postgres:18-alpine
env_file: .env
volumes: [pgdata:/var/lib/postgresql]
ports: ["127.0.0.1:5432:5432"]
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
interval: 2s
retries: 20
api:
build: .
env_file: .env
depends_on:
db: {condition: service_healthy}
volumes:
pgdata:
Pitfalls
$in healthcheck commands is interpolated by Compose; escape it as$$.- Mounting the volume at the wrong path for the image version; PostgreSQL 18 images keep data under
/var/lib/postgresql(version subdirectories), older ones under/var/lib/postgresql/data. docker compose down -vdeletes the data.
Variations
- Init scripts in
/docker-entrypoint-initdb.d/run on first start only. - Seed data with a one-off
docker compose run --rm api seed.
Further reading: Official PostgreSQL image
Reference: https://hub.docker.com/_/postgres
More Docker recipes
- Add a healthcheck to an HTTP service
- Build a layered image for a Spring Boot app
- Build a production image for a Node.js service
- Build a production image for a Python web app
- Build, cache and push images in GitHub Actions
- Build one image tag for amd64 and arm64
- Configure nginx from environment variables
- Develop with Compose and live reload