Setup with Docker
The fastest way to get a real PostgreSQL running is the official postgres Docker image. Docker downloads a ready-made copy of the database, starts it in an isolated container, and tears it down cleanly when you are done — no system-wide install, no leftover services. This lesson gets you from nothing to a running database you can connect to in a couple of commands.
You will need Docker installed and running. Everything below uses plain docker and docker compose commands.
One command to run Postgres
Section titled “One command to run Postgres”This single command pulls the image if needed and starts a database. It sets the superuser password, publishes the standard port, and stores the data in a named volume so it survives a container restart.
docker run --name pg \ -e POSTGRES_PASSWORD=secret \ -p 5432:5432 \ -v pgdata:/var/lib/postgresql/data \ -d postgres:17A quick tour of the flags:
--name pggives the container a memorable name so later commands can refer to it.-e POSTGRES_PASSWORD=secretsets the password for the defaultpostgresuser. This variable is required; the image refuses to start without it.-p 5432:5432maps the container’s PostgreSQL port to the same port on your machine, so tools on the host can connect tolocalhost:5432.-v pgdata:/var/lib/postgresql/datamounts a named volume at the directory where Postgres stores its files, so your data is not lost when the container is removed.-d postgres:17runs the official image, tag17, in the background.
A docker-compose.yml for repeatable setups
Section titled “A docker-compose.yml for repeatable setups”Typing that command every time gets old, and you often want a GUI alongside the database. A docker-compose.yml captures the whole setup in one file so you can start everything with docker compose up. This one runs PostgreSQL plus pgAdmin, a web GUI you will tour in the next lesson.
services: postgres: image: postgres:17 environment: POSTGRES_PASSWORD: secret POSTGRES_DB: appdb ports: - '5432:5432' volumes: - pgdata:/var/lib/postgresql/data
pgadmin: image: dpage/pgadmin4 environment: PGADMIN_DEFAULT_PASSWORD: secret ports: - '8080:80' depends_on: - postgres
volumes: pgdata:Save it as docker-compose.yml and start everything from that directory:
docker compose up -dPostgreSQL is now on localhost:5432 and pgAdmin on http://localhost:8080. If you would rather use a lighter GUI, swap the pgadmin service for the adminer image, which serves a single-file admin page on its own port. Either way the database service is unchanged.
How the pieces fit together
Section titled “How the pieces fit together”A container is a running copy of the image, the named volume is where the actual data files live on your machine, and clients connect over the published port. The volume is deliberately separate from the container so the data outlives any single container.
flowchart LR V[(pgdata named volume)] --> P[postgres container] P -->|port 5432| H[Host machine] H --> CLI[psql or driver] H --> GUI[pgAdmin in browser]
Verify and connect
Section titled “Verify and connect”Confirm the container is up:
docker psYou should see a row for the postgres image with a status of Up and the port mapping 0.0.0.0:5432->5432/tcp. Now connect with psql. If you have it on your host, point it at the database with a connection string:
psql "postgresql://postgres:secret@localhost:5432/postgres"No local psql? The image bundles one, so you can run it inside the container instead:
docker exec -it pg psql -U postgresEither way you land at the postgres=# prompt, ready to run SQL. When you are finished for the day, docker compose down stops everything; because the data lives in the pgdata volume, it is all still there next time you bring the stack back up.
Tips / gotchas
Section titled “Tips / gotchas”- The named volume is what makes your data persistent. Remove the container and the data stays; delete the volume and the data is gone for good.
5432is PostgreSQL’s default port andpostgresis the default superuser. Tools assume these unless told otherwise.POSTGRES_DBcreates an extra database on first startup. Without it, you still get the built-inpostgresdatabase to work in.POSTGRES_PASSWORDis mandatory for the official image. Use a real secret outside of local experiments, notsecret.- Pin a major version like
postgres:17rather thanpostgres:latestso an image update never surprises you with a different version.