Run the application with PostgreSQL¶
This chapter starts a production-shaped dependency chain: PostgreSQL becomes healthy, a one-shot container applies the PostgreSQL artifacts, and only then does the API start.
%% Compose startup
flowchart LR
P[PostgreSQL 17] -->|service_healthy| M[Migration job]
M -->|service_completed_successfully| A[FastAPI service]
A -->|/health ready| U[Client]
Inspect the Compose definition¶
name: ormdantic-todo
services:
postgres:
image: postgres:17-alpine
environment:
POSTGRES_DB: ${POSTGRES_DB:-todo}
POSTGRES_USER: ${POSTGRES_USER:-todo}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-todo}
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}']
interval: 2s
timeout: 3s
retries: 20
volumes:
- todo-postgres-data:/var/lib/postgresql/data
migrate:
build:
context: ../..
dockerfile: examples/todo_app/Dockerfile
environment: &application-environment
APP_ENV: production
DATABASE_URL: postgresql://${POSTGRES_USER:-todo}:${POSTGRES_PASSWORD:-todo}@postgres:5432/${POSTGRES_DB:-todo}
command:
- ormdantic
- migrations
- apply-dir
- /app/migrations/postgresql
- --allow-destructive
depends_on:
postgres:
condition: service_healthy
restart: 'no'
api:
build:
context: ../..
dockerfile: examples/todo_app/Dockerfile
environment: *application-environment
ports:
- '${TODO_API_PORT:-8000}:8000'
depends_on:
migrate:
condition: service_completed_successfully
healthcheck:
test:
- CMD
- python
- -c
- 'import urllib.request; urllib.request.urlopen(''http://127.0.0.1:8000/health'', timeout=2)'
interval: 5s
timeout: 3s
retries: 12
restart: unless-stopped
volumes:
todo-postgres-data:
No service mounts the Docker socket. PostgreSQL data lives in a named volume, and the runtime image runs as a non-root user. The image builds the local Ormdantic wheel in a Rust builder stage, then copies only the wheel and example into a slim Python runtime stage.
Start the stack¶
From the repository root:
docker compose -f examples/todo_app/docker-compose.yml up --build
Wait until api is healthy, then open http://127.0.0.1:8000/docs or run:
curl http://127.0.0.1:8000/health
The expected backend is postgresql. Stop containers without erasing data:
docker compose -f examples/todo_app/docker-compose.yml down
The named volume remains. Add --volumes only when you intentionally want to
delete all example data.
The default credentials are demonstration values. Override POSTGRES_DB,
POSTGRES_USER, and POSTGRES_PASSWORD locally; use managed secrets and TLS in a
real deployment. Review PostgreSQL driver behavior
before selecting URL options or relying on native schema features.