Skip to main content

Postgres with Docker

This short guide shows how to run PostgreSQL in Docker for development and small projects. You'll learn the minimal commands and a docker-compose example, how to persist data safely, how to connect, and common pitfalls to avoid.

Concept explained

  • A Postgres Docker image packages the database server; the container runs the server process.
  • Persistent data must live outside the container filesystem – use Docker volumes (recommended) or host mounts.
  • Credentials and initialization can be supplied with environment variables or init scripts.
  • For production, prefer managed databases or a PaaS-provided Postgres for backups, metrics and isolation.

Step-by-step example

  1. Run a single Postgres container (quick start)
docker network create app_network

docker volume create pg_data

docker run -d \
--name pg-dev \
--network app_network \
-e POSTGRES_USER=appuser \
-e POSTGRES_PASSWORD=secretpass \
-e POSTGRES_DB=appdb \
-v pg_data:/var/lib/postgresql/data \
-p 5432:5432 \
postgres:15
  • Replace POSTGRES_PASSWORD with a secure value.
  • The named volume pg_data holds the DB files so data survives container restarts.
  1. Connect with psql from the host (if psql is installed)
psql "postgresql://appuser:secretpass@localhost:5432/appdb"
  1. Exec into the running container to use the bundled psql
docker exec -it pg-dev psql -U appuser -d appdb
  1. Minimal docker-compose.yml (recommended for multi-service apps)
services:
db:
image: postgres:15
restart: unless-stopped
environment:
POSTGRES_USER: appuser
POSTGRES_PASSWORD: secretpass
POSTGRES_DB: appdb
volumes:
- pg_data:/var/lib/postgresql/data
networks:
- app_network

volumes:
pg_data:

networks:
app_network:

Start with: docker compose up -d db

Variations & gotchas

  • Init scripts: put .sql or .sh files in a folder mounted to /docker-entrypoint-initdb.d – they only run on first initialization.
  • Host mounts vs volumes: host mounts can cause permission and performance issues; use named volumes for portability.
  • Versions: avoid the latest tag. Pin a major/minor version (e.g., postgres:15) to prevent surprises on updates.
  • Healthchecks: add a healthcheck in docker-compose to ensure the DB is ready before your app starts.
caution

If you change the volume path or recreate the volume, you can lose data. Always back up important databases before volume removals.

Common mistakes

  • Exposing 5432 publicly without firewall rules or strong passwords.
  • Relying on container-local DB for production without backups or replicas.
  • Using POSTGRES_PASSWORD with weak values or committing them into git.
  • Running migrations while the container isn't fully ready (use healthchecks/wait-for scripts).

Best practices

  • Use named Docker volumes for persistence.
  • Pin image versions (e.g., postgres:15).
  • Keep production credentials in a secret manager or the PaaS secrets feature rather than plain files.
  • Schedule regular backups (logical dumps or file-level backups) and test restores.
  • Monitor disk usage and set appropriate max_connections / memory settings for your workload.
tip

For local development, consider a small, fixed password and a dedicated DB user. For shared dev environments or CI, use per-environment credentials.

When to use / when not to use

When to use:

  • Local development, testing, small internal projects, or prototypes.
  • When you want a lightweight DB alongside your app in Docker Compose.

When not to use:

  • High-availability production systems requiring automated backups, replicas, or managed maintenance – prefer a managed DB or the PaaS database service.

Key takeaways

  • Run Postgres in Docker using a pinned image, named volume, and explicit credentials.
  • Use healthchecks and wait-for logic so apps connect only after the DB is ready.
  • Don't expose Postgres directly to the public internet; secure credentials and backups are essential.