Running PostgreSQL in Docker

Learn how to run PostgreSQL in Docker with persistent data storage, environment-based configuration, custom initialization scripts, and proper networking for application connectivity.

Real-World Stacks

Detailed Explanation

PostgreSQL with Docker

Running PostgreSQL in Docker is ideal for development environments and testing. The official image handles initialization automatically based on environment variables:

docker run -d \
  --name postgres \
  -e POSTGRES_USER=myuser \
  -e POSTGRES_PASSWORD=mypassword \
  -e POSTGRES_DB=myapp \
  -p 5432:5432 \
  postgres:16

Environment Variables

The official PostgreSQL image supports these key variables:

Variable Purpose Default
POSTGRES_PASSWORD Superuser password (required) None
POSTGRES_USER Superuser name postgres
POSTGRES_DB Default database name Same as POSTGRES_USER
PGDATA Data directory path /var/lib/postgresql/data

Persistent Data Storage

Without a volume, database data is lost when the container is removed. Always mount a volume for the data directory:

docker run -d \
  --name postgres \
  -e POSTGRES_USER=myuser \
  -e POSTGRES_PASSWORD=mypassword \
  -e POSTGRES_DB=myapp \
  -v pgdata:/var/lib/postgresql/data \
  -p 5432:5432 \
  postgres:16

Custom Initialization Scripts

Place SQL or shell scripts in /docker-entrypoint-initdb.d/ to run them when the database is first created:

docker run -d \
  --name postgres \
  -e POSTGRES_USER=myuser \
  -e POSTGRES_PASSWORD=mypassword \
  -v pgdata:/var/lib/postgresql/data \
  -v $(pwd)/init-scripts:/docker-entrypoint-initdb.d:ro \
  -p 5432:5432 \
  postgres:16

Scripts run in alphabetical order and only on first initialization (when the data directory is empty). Common uses:

  • Creating additional databases
  • Loading seed data
  • Setting up extensions (CREATE EXTENSION pgcrypto;)
  • Creating additional users and roles

Custom PostgreSQL Configuration

Override the default postgresql.conf:

docker run -d \
  --name postgres \
  -e POSTGRES_USER=myuser \
  -e POSTGRES_PASSWORD=mypassword \
  -v pgdata:/var/lib/postgresql/data \
  -v $(pwd)/postgresql.conf:/etc/postgresql/postgresql.conf:ro \
  -p 5432:5432 \
  postgres:16 -c 'config_file=/etc/postgresql/postgresql.conf'

Or pass individual parameters directly:

docker run -d \
  --name postgres \
  -e POSTGRES_PASSWORD=mypassword \
  postgres:16 \
  -c shared_buffers=256MB \
  -c max_connections=100 \
  -c work_mem=4MB

Connecting from Another Container

Use Docker networking for container-to-container communication:

docker network create app-net

docker run -d \
  --name postgres \
  --network app-net \
  -e POSTGRES_PASSWORD=mypassword \
  -v pgdata:/var/lib/postgresql/data \
  postgres:16

docker run -d \
  --name api \
  --network app-net \
  -e DATABASE_URL=postgres://postgres:mypassword@postgres:5432/postgres \
  my-api-image

Notice the connection string uses postgres (the container name) as the hostname.

Production Docker Run

docker run -d \
  --name postgres \
  --restart unless-stopped \
  --memory 2g \
  --cpus 2 \
  --network app-net \
  -e POSTGRES_USER=appuser \
  -e POSTGRES_PASSWORD_FILE=/run/secrets/db_password \
  -e POSTGRES_DB=production \
  -v pgdata:/var/lib/postgresql/data \
  -v $(pwd)/init:/docker-entrypoint-initdb.d:ro \
  postgres:16 \
  -c shared_buffers=512MB \
  -c max_connections=200

Use Case

Setting up a PostgreSQL database for a development team, with persistent storage, initialization scripts that create the schema and seed data, and network connectivity to the application container.

Try It — Docker Run Command Builder

Open full tool