Persisting PostgreSQL

Persisting BookNest's PostgreSQL Data

postgres:18 declares VOLUME /var/lib/postgresql. PostgreSQL 18 1,289 's image changed the layout: data now lives in a version-specific subdirectory, /var/lib/postgresql/18/docker, and the image refuses to start if you mount a volume at the old /var/lib/postgresql/data path. Mount the parent directory. Seed the catalog with the API, change a price, then replace the database container entirely:

The catalog survives a new PostgreSQL containerShell
docker network create l3-bn >/dev/null
db() { docker run -d --name l3-db --network l3-bn --network-alias postgres \
  --env-file ../booknest.env -v l3-pgdata:/var/lib/postgresql postgres:18 >/dev/null; }
db; sleep 6
docker run --rm --network l3-bn -e PGHOST=postgres l3-booknest-api:1.2 \
  node -e "require('./db').init().then(() => { console.log('seeded'); process.exit(0) })"
docker exec l3-db psql -U booknest -c "UPDATE books SET price = 19.99 WHERE id = 3"
docker rm -f l3-db >/dev/null
db; sleep 4
docker exec l3-db psql -U booknest -tAc "SELECT title, price FROM books WHERE id = 3"
docker exec l3-db ls /var/lib/postgresql/18
docker inspect l3-db --format '{{range .Mounts}}{{.Type}} {{.Name}} -> {{.Destination}}{{end}}'
Output
seeded
UPDATE 1
Salt and Saffron|19.99
docker
volume l3-pgdata -> /var/lib/postgresql

The second container found an initialized cluster in the volume, skipped initdb and served the changed price. The image's entrypoint initializes a database only when the data directory is empty, so POSTGRES_PASSWORD and the other POSTGRES_* variables are read once, on first start: changing them later does not change the existing database. To start over, remove the volume with docker volume rm l3-pgdata. Upgrading to PostgreSQL 19 later means a dump and restore or pg_upgrade; the 18 directory keeps an old cluster from being opened by a newer server by accident.