Stack Module
The stack module manages a local backend service stack for development — PostgreSQL, Keycloak, PostgREST, and Traefik — using Docker Compose. It handles DB initialization, Keycloak realm import, and JWK key fetching automatically on the first run.
Services
| Service | Image | URL / Port | Purpose |
|---|---|---|---|
postgres | postgres:16-alpine | localhost:25432 | Database |
keycloak | quay.io/keycloak/keycloak:26.6 | http://keycloak.localhost | Auth server |
postgrest | postgrest/postgrest:latest | http://api.localhost | REST API |
traefik | traefik:v3.3 | Port 80 / dashboard localhost:8080 | Reverse proxy |
Workflow
┌──────────────────────────────────────────────────────────────────┐
│ stack up (two-phase) │
├──────────────────────────────────────────────────────────────────┤
│ │
│ Phase 1 Start postgres + traefik → wait for health │
│ │ │
│ Phase 2 Apply DB: infra SQL + migrations + seeds │
│ │ │
│ Phase 3 Start keycloak + postgrest → wait for health │
│ │ │
│ Phase 4 First run only: import realm → fetch JWKs │
│ │ │
│ Mark stack as initialized (is_initial = false in DB) │
└──────────────────────────────────────────────────────────────────┘
Phase 4 only runs when the database has no is_initial = false record in postkit.stack_config. It resets automatically when volumes are wiped with stack down --volumes.
Commands
| Command | Description |
|---|---|
up | Start all or selected services |
down | Stop services, optionally remove volumes |
status | Show service health |
logs | Tail service logs |
restart | Restart one or more services |
keys | Fetch Keycloak JWKs and client secrets |
realm | Re-import the Keycloak realm template |
Prerequisites
- Docker Desktop installed and running
- Docker Compose V2 (included with Docker Desktop 4.x+)
- Project initialized with
postkit init
Quick Start
# Initialize (creates infra SQL, realm template, provider JARs)
postkit init
# Start full stack — first run imports realm and fetches JWKs automatically
postkit stack up
# Check status
postkit stack status
# Stop (keeps data volumes)
postkit stack down
# Full reset — wipes all data, runs initialization again on next up
postkit stack down --volumes
Configuration
Stack configuration is split across two files:
postkit.config.json (committed)
{
"name": "myapp_a3f2b1c0",
"stack": {
"postgres": { "port": 25432, "database": "postkit" },
"keycloak": {
"realm": "postkit",
"realmTemplate": ".postkit/auth/realm/postkit.json",
"clients": ["app"]
},
"postgrest": { "dbSchema": "public", "dbAnonRole": "anon" },
"traefik": { "httpPort": 80, "dashboardPort": 8080 }
}
}
postkit.secrets.json (gitignored)
Auto-generated on first stack up. Missing passwords and JWKs are generated automatically.
{
"stack": {
"postgres": { "user": "postgres", "password": "<auto-generated>" },
"keycloak": { "adminUser": "admin", "adminPassword": "<auto-generated>" }
}
}
is_initial State
The stack tracks whether first-run initialization has completed in the postkit.stack_config database table. This means the state resets automatically when you wipe volumes — no manual cleanup needed.
| How to reset | When to use |
|---|---|
postkit stack down --volumes | Full reset — wipes all data and re-initializes on next stack up |
postkit stack realm | Re-import realm template only |
postkit stack keys | Re-fetch JWKs and client secrets only |
Output Structure
.postkit/
├── auth/
│ ├── realm/
│ │ └── postkit.json # Realm template (committed)
│ └── providers/ # Keycloak JARs (gitignored, rebuilt by init)
└── stack/
└── docker-compose.yml # Generated compose file (gitignored)