Setting Up Local PostgreSQL with Docker Compose

Running PostgreSQL in Docker is one of the most reliable ways to develop locally without installing PostgreSQL directly onto your system. Docker Compose simplifies the entire lifecycle: creating containers, managing volumes, setting configuration, and linking services like pgAdmin.
This updated guide includes improved configuration, optional pgAdmin support, health checks, persistent storage, and environment safety tips.
Prerequisites
You need the following installed:
- Docker
- Docker Compose
- Optional: pgAdmin or DBeaver for GUI management
Step 1: Create a Project Directory
mkdir postgres-docker
cd postgres-dockerOrganizing your PostgreSQL setup inside a dedicated project folder keeps your environment clean and portable.
Step 2: Create an Improved docker-compose.yml
The following configuration includes:
- PostgreSQL with persistent storage
- Optional initialization SQL scripts
- Health checks
- A dedicated network
- Optional pgAdmin container
version: '3.9'
services:
postgres:
image: postgres:16
container_name: local-postgres
restart: unless-stopped
environment:
POSTGRES_USER: postgres_user
POSTGRES_PASSWORD: postgres_password
POSTGRES_DB: postgres_db
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
- ./init:/docker-entrypoint-initdb.d
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres_user"]
interval: 5s
timeout: 3s
retries: 5
networks:
- pgnet
pgadmin:
image: dpage/pgadmin4:latest
container_name: pgadmin
restart: unless-stopped
environment:
PGADMIN_DEFAULT_EMAIL: admin@example.com
PGADMIN_DEFAULT_PASSWORD: admin123
ports:
- "5050:80"
depends_on:
- postgres
networks:
- pgnet
volumes:
postgres_data:
networks:
pgnet:Features added in this improved version
- Health checks ensure PostgreSQL is ready before other services connect.
- pgAdmin service gives you a full GUI at
http://localhost:5050. - Initialization folder (
./init) lets you pre-load tables, schemas, or seed data. - Named Docker network isolates database traffic.
Step 3: Optional SQL Initialization
Create an init folder:
mkdir initThen add init/001-create-tables.sql:
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);This script runs automatically when the container is first created.
Step 4: Start the Services
docker-compose up -dThis pulls the images, creates the containers, and initializes your PostgreSQL database.
Check running services:
docker psStep 5: Connect to PostgreSQL
Using psql:
psql -h localhost -p 5432 -U postgres_user -d postgres_dbUsing pgAdmin:
Open:
http://localhost:5050Add a new server:
- Host: postgres
- User: postgres_user
- Password: postgres_password
Step 6: Stop and Remove Containers Safely
docker-compose downVolumes persist, so your data remains intact.
To remove everything including data:
docker-compose down -vStep 7: Useful Commands
Restart PostgreSQL
docker-compose restart postgresReset the database completely
docker-compose down -v
docker-compose up -dEnter PostgreSQL shell inside container
docker exec -it local-postgres psql -U postgres_user -d postgres_dbTips and Best Practices
Use .env instead of hardcoding credentials
Create .env:
POSTGRES_USER=postgres_user
POSTGRES_PASSWORD=postgres_password
POSTGRES_DB=postgres_dbAnd replace variables in docker-compose.yml.
Always mount a persistent volume
Never rely on container-only storage.
Use versioned SQL migrations
Use tools like:
- Flyway
- Prisma Migrate
- Liquibase
Summary
You now have a fully-featured PostgreSQL instance running locally with Docker Compose. This setup is production-like, supports persistence, enables optional pgAdmin GUI management, and gives you complete control over initialization and networking.
This environment is ideal for:
- Local development
- API testing
- Microservice environments
- Team-shared reproducible setups