🐘 Guide · PostgreSQL

How to Run PostgreSQL in Docker
(with Docker Compose)

Docker gives you a clean, reproducible Postgres environment in under a minute — no system install required. This guide covers the one-liner quickstart, a production-ready Docker Compose setup with persistent volumes, and when self-hosting Postgres in Docker stops being worth the effort.

Quick Start — docker run

The fastest way to get Postgres running locally:

bash
docker run -d \
  --name my-postgres \
  -e POSTGRES_USER=myuser \
  -e POSTGRES_PASSWORD=mypassword \
  -e POSTGRES_DB=mydb \
  -p 5432:5432 \
  postgres:17

Connect with psql:

bash
psql postgresql://myuser:mypassword@localhost:5432/mydb
⚠️

Data warning: without a volume mount, all data lives inside the container. Run docker rm my-postgres and it's gone permanently. Use Docker Compose with a named volume for anything you care about.

The Real Setup — Docker Compose + Named Volume

Docker Compose is how most teams actually run Postgres locally. It handles startup order, environment variables, volume mounts, and health checks in one file you can commit to git.

docker-compose.yml
services:
  postgres:
    image: postgres:17
    restart: unless-stopped
    environment:
      POSTGRES_USER: myuser
      POSTGRES_PASSWORD: mypassword
      POSTGRES_DB: mydb
    ports:
      - "5432:5432"
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U myuser -d mydb"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  pgdata:
docker compose up -dStart in background, data persists in volume
docker compose stopStop containers, volume and data untouched
docker compose downRemove containers, volume safe
docker compose down -vRemove containers AND volume — data is gone
📌

Pin the version. Use postgres:17 not postgres:latest. The latest tag will eventually bump a major version and break your migrations without warning.

Seeding Schema on First Start

The official image runs any .sql or .sh files in /docker-entrypoint-initdb.d/ on first boot. Mount an init script to seed schema or create extra databases:

docker-compose.yml (excerpt)
    volumes:
      - pgdata:/var/lib/postgresql/data
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql

Only runs when pgdata is empty (fresh volume). Safe to leave in — ignored on all subsequent starts.

Why Developers Run Postgres in Docker

📦
Reproducible environments

Pin postgres:17.2 and every developer, CI job, and staging server runs the exact same version — no "works on my machine" drift.

🔀
No system conflicts

Run Postgres 14, 15, 16, and 17 side by side. Each project gets its own isolated instance with no port or binary conflicts.

⚙️
CI pipeline ready

Spin up a fresh DB per test run, run migrations, run tests, tear down. GitHub Actions and GitLab CI support Docker services natively.

🤝
Team consistency

Commit docker-compose.yml to the repo. New developers run one command and have a working database in 30 seconds.

Where It Gets Hard

  • Backups are your job. No automatic pg_dump, no point-in-time recovery, no off-site copy. You build this or you skip it.
  • Production ops don't disappear. Disk fills up, major version upgrades need pg_upgrade, replicas need manual setup. Docker moves the ops burden — it doesn't remove it.
  • Volume performance on Mac and Windows. Docker Desktop mounts are noticeably slower than native disk for write-heavy workloads.
  • Container networking trips teams up. Other containers reach Postgres via the service name (postgres), not localhost. Health checks prevent premature connections.
  • One command wipes everything. docker compose down -v deletes the volume silently. No confirmation, no recycle bin.

Skip the Ops for Your Production Database

Docker Postgres is great for local dev and CI. When you're shipping to real users — get a managed Postgres database in 30 seconds, backups included, zero ops.

Get a Free Postgres Database →

Free tier · No credit card · Instant connection string

Frequently Asked Questions

Does Docker Postgres persist data after container restart?

Yes — as long as you have a named volume mounted to /var/lib/postgresql/data. docker compose stop then docker compose up preserves everything. docker compose down -v removes the volume and wipes all data.

What port does Postgres use in Docker?

Port 5432 — same as a native install. Map it with -p 5432:5432 or ports: ["5432:5432"] in Docker Compose to reach it from your host machine.

Should I run Postgres in Docker in production?

It works, but you own everything: backups, HA, major version upgrades, disk monitoring. For most indie projects and startups, a managed Postgres service saves significant time and reduces risk.

Which Postgres version tag should I use?

Pin a specific major version like postgres:17 rather than postgres:latest. The latest tag will eventually jump to a new major version and silently break your migrations.