Skip to main content

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

ServiceImageURL / PortPurpose
postgrespostgres:16-alpinelocalhost:25432Database
keycloakquay.io/keycloak/keycloak:26.6http://keycloak.localhostAuth server
postgrestpostgrest/postgrest:latesthttp://api.localhostREST API
traefiktraefik:v3.3Port 80 / dashboard localhost:8080Reverse 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

CommandDescription
upStart all or selected services
downStop services, optionally remove volumes
statusShow service health
logsTail service logs
restartRestart one or more services
keysFetch Keycloak JWKs and client secrets
realmRe-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 resetWhen to use
postkit stack down --volumesFull reset — wipes all data and re-initializes on next stack up
postkit stack realmRe-import realm template only
postkit stack keysRe-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)