Running PostgreSQL in Docker
A new developer joins Pedal and needs a local database that matches production. Installing packages on every laptop drifts over time. One Docker command gives everyone the same version — as long as you know the one mistake that silently deletes the data.
The rule
Pin the tag, set a password, put the data in a volume.
docker run -d --name pedal-db \
-e POSTGRES_PASSWORD=change-me \
-e POSTGRES_DB=pedal \
-p 5432:5432 \
-v pedal-data:/var/lib/postgresql/data \
postgres:17- Pin the tag.
postgres:17stays on major version 17 and picks up minor fixes when you pull.postgres:latestwould one day jump to a new major version, and a data directory from the old one will refuse to start. - Set a password. The official image will not start without
POSTGRES_PASSWORD(unless you deliberately choose an insecure trust mode).POSTGRES_USERandPOSTGRES_DBare optional and default topostgres. - Put the data in a volume. A container's own filesystem disappears with the container.
-v pedal-data:/var/lib/postgresql/datastores the cluster in a named volume that survivesdocker rm. (Images for version 18 and later expect the volume at/var/lib/postgresqlinstead; check the image notes when you change major version.)
-p 5432:5432 publishes the port so tools on your machine can connect to localhost:5432.
Two more behaviours of the official image:
- Files in
/docker-entrypoint-initdb.d/(.sqlor.sh) run only when the data directory is empty, the first time. Mount your schema there to create it automatically. docker exec -it pedal-db psql -U postgres -d pedalopens psql inside the container.
In production, many teams skip running PostgreSQL themselves and use a managed cloud service (Amazon RDS, Google Cloud SQL, Azure Database for PostgreSQL). The provider handles installation, patches and backups; you still own roles, settings and queries, and you trade some control, such as superuser access, for that convenience.
The shortcut
Before you run the container, ask: "If I delete this container right now, what is lost?" The answer must be "nothing": the data is in the volume, and the version is in the tag.
The command they ran
docker run -e POSTGRES_PASSWORD=x postgreswith no volume and no tag.
A related surprise: changing POSTGRES_PASSWORD on an existing volume does nothing. The variable is used only during first initialisation; afterwards, change passwords with ALTER ROLE.
Drills
Answer fast — trust the rule.
Why pin the image to postgres:17 instead of postgres:latest?
What happens to the tables if you remove a container that had no volume?
You add schema.sql to /docker-entrypoint-initdb.d/ and restart a container that already has data. What happens?
Which environment variable must be set for the official image to start normally?
Remember
- Pin the tag, set a password, put the data in a volume.
- Ask "if I delete this container, what is lost?" The answer must be nothing.
- Init scripts and POSTGRES_PASSWORD only matter the first time the volume is empty.
