M
MeshWorld.
HowTo PostgreSQL Docker Database Docker Compose Developer Tools Backend 5 min read

How to Run PostgreSQL Locally with Docker

By Vishnu Damwala

Running PostgreSQL locally used to mean a full install, fighting with config files, and dealing with version conflicts. With Docker, it’s a one-liner — and you can have multiple versions running side by side if you need them.


Quick start — running in 60 seconds

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

That’s it. PostgreSQL 16 is running on localhost:5432.

Connect with psql:

# Using Docker (no local psql needed)
docker exec -it postgres psql -U myuser mydb

# Using local psql if you have it installed
psql -h localhost -U myuser mydb

Check it’s running:

docker ps
# CONTAINER ID  IMAGE              PORTS                   NAMES
# abc123        postgres:16-alpine 0.0.0.0:5432->5432/tcp  postgres

The problem with the quick start: data disappears

When you docker rm the container, all your data goes with it. For serious development, you need persistent storage.


Proper setup — with persistent storage

docker run -d \
  --name postgres \
  -e POSTGRES_USER=myuser \
  -e POSTGRES_PASSWORD=mypassword \
  -e POSTGRES_DB=mydb \
  -p 5432:5432 \
  -v postgres_data:/var/lib/postgresql/data \
  --restart unless-stopped \
  postgres:16-alpine

The -v postgres_data:/var/lib/postgresql/data flag creates a Docker named volume. Your data lives in that volume even if you remove and recreate the container.

To see your volumes:

docker volume ls
# DRIVER    VOLUME NAME
# local     postgres_data

docker-compose — for real projects

For any project you’re actively developing, use docker-compose.yml so your database config lives next to your code:

services:
  db:
    image: postgres:16-alpine
    container_name: myapp_db
    environment:
      POSTGRES_USER: myuser
      POSTGRES_PASSWORD: mypassword
      POSTGRES_DB: mydb
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
    restart: unless-stopped
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U myuser -d mydb"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  postgres_data:

Start it:

docker compose up -d

# Check it's healthy
docker compose ps
# NAME         STATUS          PORTS
# myapp_db     Up (healthy)    0.0.0.0:5432->5432/tcp

Stop and restart without losing data:

docker compose stop   # stops containers, data stays
docker compose start  # starts again
docker compose down   # removes containers, data STAYS in volume
docker compose down -v # removes containers AND volumes (data gone)

Connecting from your application

Your .env file:

DATABASE_URL=postgresql://myuser:mypassword@localhost:5432/mydb

Connection string format:

postgresql://[user]:[password]@[host]:[port]/[database]

Works with any client:

  • Prisma: datasource db { url = env("DATABASE_URL") }
  • node-postgres (pg): new Pool({ connectionString: process.env.DATABASE_URL })
  • SQLAlchemy: create_engine(os.environ["DATABASE_URL"])
  • GORM: built-in postgres dialect

Connect with a GUI client

Your Docker PostgreSQL is just a regular postgres server on port 5432. Connect with any GUI tool:

ToolConnection
TablePlusHost: localhost, Port: 5432, User/DB/Pass as set
DBeaverSame — PostgreSQL connection type
pgAdminAdd server: localhost:5432
DataGripNew data source → PostgreSQL
VS CodeSQLTools extension → PostgreSQL driver

Running multiple PostgreSQL versions

Docker makes version testing trivial:

# PostgreSQL 14 on port 5433
docker run -d --name pg14 \
  -e POSTGRES_PASSWORD=pass \
  -p 5433:5432 \
  postgres:14-alpine

# PostgreSQL 16 on port 5432
docker run -d --name pg16 \
  -e POSTGRES_PASSWORD=pass \
  -p 5432:5432 \
  postgres:16-alpine

Connect to whichever you need by changing the port.


Load a SQL dump into the container

# Pipe a dump file into psql inside the container
docker exec -i postgres psql -U myuser mydb < backup.sql

# Or copy the file in first
docker cp backup.sql postgres:/tmp/
docker exec -it postgres psql -U myuser mydb -f /tmp/backup.sql

Dump the database out of the container

# Dump to local file
docker exec postgres pg_dump -U myuser mydb > backup.sql

# Compressed dump
docker exec postgres pg_dump -U myuser -Fc mydb > backup.dump

Common commands

# See container logs
docker logs postgres
docker logs -f postgres  # follow

# Enter a bash shell inside the container
docker exec -it postgres bash

# Connect to psql directly
docker exec -it postgres psql -U myuser mydb

# Restart the container
docker restart postgres

# Stop without removing
docker stop postgres

# Remove container (data stays if you used a volume)
docker rm postgres

# Remove container and volume
docker stop postgres && docker rm postgres
docker volume rm postgres_data

Environment variables reference

VariableRequiredDefaultWhat it sets
POSTGRES_PASSWORDYesPassword for the user
POSTGRES_USERNopostgresUsername
POSTGRES_DBNoSame as userDefault database
PGDATANo/var/lib/postgresql/dataData directory

The Docker setup takes about 60 seconds and gives you a clean, isolated database that you can tear down and rebuild any time. No leftover system packages, no version conflicts, no permission issues.

Keep these handy: PostgreSQL Cheat Sheet | How to Debug a Slow SQL Query