Part 9: Postgres in a container
SQLite from Part 7: Real persistence with SQLite is perfect for local work, but it's a single file on disk, not the kind of database a deployed app runs against. On a real server we use Postgres, so we start using it now. Postgres is a server rather than a file, and we don't want to install and manage it on a laptop. So we run it the easy way, as a Docker container, with the app still running locally and pointed at it.
The backend already chooses its database from DATABASE_URL (see
Part 7: Real persistence with SQLite), so moving from SQLite to Postgres
is a configuration change, not a code change.
Run Postgres in Docker
Start a Postgres container with a name, the credentials, a published port, and a named volume so the data survives restarts:
docker run -d --name snake-db \
-e POSTGRES_USER=snakearena \
-e POSTGRES_PASSWORD=snakearena \
-e POSTGRES_DB=snakearena \
-p 5432:5432 \
-v snake_pgdata:/var/lib/postgresql/data \
postgres:16-alpine
The -v snake_pgdata:/var/lib/postgresql/data volume lives outside the container,
so stopping or removing the container keeps every account and score.
Point the app at Postgres
Change backend/.env to use the container instead of the SQLite file:
DATABASE_URL=postgresql://snakearena:snakearena@localhost:5432/snakearena
The host is localhost because the container publishes port 5432 to your
machine.
Start the app the usual way:
make dev
The backend creates its tables in Postgres on the first run. Sign up, submit a
score, then restart the database with docker restart snake-db and reload. The
data is still there, because it lives in the named volume.
Stop the database when you're done:
docker stop snake-db
Running the database in one command and the app in another works, but it's two things to start, in the right order, every time. In Part 10: Docker Compose we wrap the app and Postgres into a single Compose file so one command brings the whole stack up.