Learn how to set up and use the complete FastAPI Docker development environment included with API Forge. This guide covers the local Docker Compose stack with PostgreSQL, Redis, Temporal, and Keycloak, providing a production-like development experience for your FastAPI application.
API Forge includes a fully containerized development environment that runs all required services locally using Docker Compose. This FastAPI development setup includes:
- PostgreSQL 16 - Production-grade database (port 5433)
- Redis 7 - Caching and session storage (port 6380)
- Temporal Server - Workflow orchestration (port 7233)
- Temporal Web UI - Workflow monitoring dashboard (port 8082)
- Keycloak - OIDC authentication server (port 8080)
- Pre-configured test users - Ready-to-use authentication
All services are automatically configured and networked together, with different ports from production to allow running both environments simultaneously.
Start the entire development environment with one command:
# Start all services
uv run api-forge-cli deploy up dev
# Wait 30-60 seconds for services to initialize
# Check service status
uv run api-forge-cli deploy status dev
# Start your FastAPI application
uvicorn src_main:app --reloadYour FastAPI application will be available at http://localhost:8000 with automatic reload on code changes.
API Forge provides convenient CLI commands for managing the Docker development environment:
uv run api-forge-cli deploy up devStarts all Docker services defined in docker-compose.dev.yml:
- Creates Docker network
dev-network - Starts PostgreSQL with dev database
- Starts Redis with dev configuration
- Starts Temporal server and Web UI
- Starts Keycloak with test realm and users
- Waits for services to become healthy
uv run api-forge-cli deploy down devStops all running services but preserves data volumes. Data in PostgreSQL and Redis is retained for the next start.
uv run api-forge-cli deploy status devShows the current status of all development services:
Development Environment Status:
✓ Keycloak: Running (Healthy)
✓ PostgreSQL: Running (Healthy)
✓ Redis: Running (Healthy)
✓ Temporal: Running (Healthy)
✓ Temporal UI: Running (Healthy)
# View logs for specific service (using docker-compose directly)
docker-compose -f docker-compose.dev.yml logs postgres
docker-compose -f docker-compose.dev.yml logs redis
docker-compose -f docker-compose.dev.yml logs keycloak
docker-compose -f docker-compose.dev.yml logs temporal
# Follow logs (real-time)
docker-compose -f docker-compose.dev.yml logs -f postgresuvicorn src_main:app --reloadStarts your FastAPI application with:
- Auto-reload on code changes
- Connection to development PostgreSQL (port 5433)
- Connection to development Redis (port 6380)
- Connection to development Temporal (port 7233)
- Development OIDC configuration with Keycloak
Purpose: Primary database for development
Configuration:
- Host:
localhost(orpostgresfrom within Docker) - Port:
5433(different from production's 5432) - Database:
appdb - User:
devuser - Password:
devpass - Version: PostgreSQL 16
Connection String:
postgresql://devuser:devpass@localhost:5433/appdb
Direct Access:
# Using docker exec
docker exec -it api-forge-postgres-dev psql -U devuser -d appdb
# Using psql directly
psql -h localhost -p 5433 -U devuser -d appdbData Persistence:
Data is stored in Docker volume postgres_data_dev. To reset the database:
uv run api-forge-cli deploy down dev
docker volume rm api-forge-postgres-data-dev
uv run api-forge-cli deploy up devPurpose: Session storage, caching, and rate limiting
Configuration:
- Host:
localhost(orredisfrom within Docker) - Port:
6380(different from production's 6379) - Password:
devredispass - Version: Redis 7
Connection String:
redis://:devredispass@localhost:6380/0
Direct Access:
# Using docker exec
docker exec -it api-forge-redis-dev redis-cli -a devredispass
# Example commands in redis-cli
> KEYS * # List all keys
> GET session:sess_abc123 # Get session data
> TTL session:sess_abc123 # Check expiration
> FLUSHDB # Clear all data (use carefully!)Data Persistence:
Data is stored in Docker volume redis_data_dev.
Purpose: Distributed workflow orchestration
Configuration:
- Server:
localhost:7233(gRPC endpoint) - Web UI:
http://localhost:8082 - Namespace:
default - Version: Temporal 1.29.0
Web UI Features:
- View all workflows and activities
- Inspect workflow execution history
- Search workflows by status or ID
- Monitor task queues
- View worker status
Direct Access:
# Using temporal CLI (if installed)
temporal workflow list --namespace default
# View workflow details
temporal workflow describe --workflow-id my-workflow-idPurpose: Local OIDC authentication provider for testing
Configuration:
- URL:
http://localhost:8080 - Admin Console:
http://localhost:8080/admin - Admin User:
admin/admin - Realm:
test-realm - Client ID:
test-client - Client Secret:
test-client-secret
Pre-configured Test Users:
-
testuser1
- Email:
testuser1@example.com - Password:
password123 - Name: Test User One
- Email:
-
testuser2
- Email:
testuser2@example.com - Password:
password123 - Name: Test User Two
- Email:
Testing Authentication:
# Login with Keycloak
curl -X GET 'http://localhost:8000/auth/web/login?provider=keycloak'
# Or visit in browser
open http://localhost:8000/auth/web/login?provider=keycloakKeycloak Setup Script:
The Keycloak service runs an automatic setup script (src/dev/setup_keycloak.py) that:
- Creates the
test-realm - Configures the
test-clientwith correct redirect URIs - Creates test users with verified emails
- Is idempotent (safe to run multiple times)
The development environment uses these environment variables (from .env):
# Application
APP_ENVIRONMENT=development
APP_NAME=My API
# Database (development)
DATABASE_URL=postgresql://devuser:devpass@localhost:5433/appdb
# Redis (development)
REDIS_URL=redis://:devredispass@localhost:6380/0
# Temporal
TEMPORAL_URL=localhost:7233
TEMPORAL_NAMESPACE=default
# Keycloak (development only)
KEYCLOAK_ENABLED=true
KEYCLOAK_ISSUER=http://localhost:8080/realms/test-realm
OIDC_KEYCLOAK_CLIENT_ID=test-client
OIDC_KEYCLOAK_CLIENT_SECRET=test-client-secret
# Session secrets (CHANGE IN PRODUCTION!)
SESSION_SIGNING_SECRET=dev-session-secret-change-in-production
CSRF_SIGNING_SECRET=dev-csrf-secret-change-in-production-
Start services (one time per day/session):
uv run api-forge-cli deploy up dev
-
Wait for services to be ready (30-60 seconds):
uv run api-forge-cli deploy status dev
-
Initialize database (first time only):
uv run api-forge-init-db
-
Start FastAPI application:
uvicorn src_main:app --reload
-
Make code changes - FastAPI auto-reloads
-
Test authentication:
- Visit http://localhost:8000/docs
- Click "Login with Keycloak"
- Use
testuser1@example.com/password123
-
View Temporal workflows:
- Visit http://localhost:8082
-
Run tests:
# Unit tests uv run pytest tests/unit/ # Integration tests (need dev environment) uv run pytest tests/integration/
-
Stop services (end of day):
uv run api-forge-cli deploy down dev
When you change SQLModel models:
# Re-initialize database (WARNING: drops all data)
uv run api-forge-init-db
# Or manually create tables
uv run python -c "
from src.app.runtime.config import get_config
from src.app.core.database import init_db
config = get_config()
init_db(config.database.connection_string)
"For production-grade migrations, consider adding Alembic to your project.
PostgreSQL Connection Issues:
# Check if PostgreSQL is running
docker ps | grep postgres
# Check PostgreSQL logs
docker-compose -f docker-compose.dev.yml logs postgres
# Verify port is listening
netstat -an | grep 5433
# Test connection
psql -h localhost -p 5433 -U devuser -d appdb -c "SELECT version();"Redis Connection Issues:
# Check if Redis is running
docker ps | grep redis
# Check Redis logs
docker-compose -f docker-compose.dev.yml logs redis
# Test connection
docker exec -it api-forge-redis-dev redis-cli -a devredispass ping
# Should respond: PONGTemporal Connection Issues:
# Check if Temporal is running
docker ps | grep temporal
# Check Temporal logs
docker-compose -f docker-compose.dev.yml logs temporal
# Access Web UI
open http://localhost:8082Keycloak Issues:
# Check Keycloak logs
docker-compose -f docker-compose.dev.yml logs keycloak
# Verify realm exists
curl http://localhost:8080/realms/test-realm/.well-known/openid-configuration
# Access admin console
open http://localhost:8080/admin
# Login: admin / adminIf you see "port already in use" errors, another service is using the development ports:
Check what's using a port:
# On Linux
sudo netstat -tlnp | grep :8080
# On macOS
lsof -i :8080Common conflicts:
- 5433: Another PostgreSQL instance
- 6380: Another Redis instance
- 7233: Another Temporal server
- 8080: Another web server or Keycloak
- 8082: Another Temporal UI
Solutions:
- Stop the conflicting service
- Change ports in
docker-compose.dev.yml - Update corresponding environment variables
To start fresh with empty databases:
# Stop services
uv run api-forge-cli deploy down dev
# Remove volumes
docker volume rm api-forge-postgres-data-dev
docker volume rm api-forge-redis-data-dev
docker volume rm api-forge-temporal-data-dev
# Start services
uv run api-forge-cli deploy up dev
# Re-initialize database
uv run api-forge-init-db# Backup PostgreSQL
docker exec api-forge-postgres-dev pg_dump -U devuser appdb > backup.sql
# Restore PostgreSQL
docker exec -i api-forge-postgres-dev psql -U devuser appdb < backup.sql
# Backup Redis (saves RDB snapshot)
docker exec api-forge-redis-dev redis-cli -a devredispass SAVE
docker cp api-forge-redis-dev:/data/dump.rdb redis-backup.rdbThe development environment intentionally differs from production:
| Feature | Development | Production |
|---|---|---|
| PostgreSQL Port | 5433 | 5432 |
| Redis Port | 6380 | 6379 |
| Database User | devuser | appuser |
| Passwords | Hardcoded | From secrets |
| TLS/SSL | Disabled | Required |
| Keycloak | Included | External provider |
| Session Secret | Hardcoded | Random generated |
| Cookie Secure Flag | False | True |
| Docker Network | dev-network | App-specific |
These differences allow running both environments simultaneously and make local development easier.
The development environment is defined in docker-compose.dev.yml:
services:
postgres:
image: postgres:16
container_name: api-forge-postgres-dev
ports:
- "5433:5432"
environment:
POSTGRES_USER: devuser
POSTGRES_PASSWORD: devpass
POSTGRES_DB: appdb
volumes:
- postgres_data_dev:/var/lib/postgresql/data
networks:
- dev-network
healthcheck:
test: ["CMD-SHELL", "pg_isready -U devuser"]
interval: 5s
timeout: 5s
retries: 5
redis:
image: redis:7
container_name: api-forge-redis-dev
ports:
- "6380:6379"
command: redis-server --requirepass devredispass
volumes:
- redis_data_dev:/data
networks:
- dev-network
healthcheck:
test: ["CMD", "redis-cli", "-a", "devredispass", "ping"]
interval: 5s
timeout: 5s
retries: 5
temporal:
image: temporalio/auto-setup:1.29.0
container_name: api-forge-temporal-dev
ports:
- "7233:7233"
environment:
- DB=postgresql
- DB_PORT=5432
- POSTGRES_USER=devuser
- POSTGRES_PWD=devpass
- POSTGRES_SEEDS=postgres
depends_on:
postgres:
condition: service_healthy
networks:
- dev-network
temporal-ui:
image: temporalio/ui:latest
container_name: api-forge-temporal-ui-dev
ports:
- "8082:8080"
environment:
- TEMPORAL_ADDRESS=temporal:7233
depends_on:
- temporal
networks:
- dev-network
keycloak:
image: quay.io/keycloak/keycloak:latest
container_name: api-forge-keycloak-dev
ports:
- "8080:8080"
environment:
- KEYCLOAK_ADMIN=admin
- KEYCLOAK_ADMIN_PASSWORD=admin
command: start-dev
networks:
- dev-network
volumes:
postgres_data_dev:
redis_data_dev:
temporal_data_dev:
networks:
dev-network:
driver: bridgeYou can customize the development environment by editing docker-compose.dev.yml:
Change PostgreSQL version:
postgres:
image: postgres:15 # Change from 16Add pgAdmin:
pgadmin:
image: dpage/pgadmin4
ports:
- "5050:80"
environment:
PGADMIN_DEFAULT_EMAIL: admin@example.com
PGADMIN_DEFAULT_PASSWORD: admin
networks:
- dev-networkAdd Redis Commander:
redis-commander:
image: rediscommander/redis-commander
ports:
- "8081:8081"
environment:
- REDIS_HOSTS=redis:redis:6379:0:devredispass
networks:
- dev-networkCheck Docker is running:
docker psCheck for existing containers:
docker ps -a | grep api-forge
# Remove old containers if needed
docker rm api-forge-postgres-dev api-forge-redis-devCheck disk space:
docker system df
# Clean up if needed
docker system pruneVerify services are healthy:
uv run api-forge-cli deploy status devCheck environment variables:
cat .env | grep -E "DATABASE_URL|REDIS_URL|TEMPORAL_URL"Test connectivity from host:
# PostgreSQL
psql -h localhost -p 5433 -U devuser -d appdb -c "SELECT 1;"
# Redis
redis-cli -h localhost -p 6380 -a devredispass PING
# Temporal (requires grpcurl)
grpcurl -plaintext localhost:7233 listDocker resource limits:
- Increase Docker Desktop memory (Preferences > Resources)
- Recommended: 4GB+ RAM for all services
Volume performance on macOS:
- Consider using Docker named volumes instead of bind mounts
- Use
:delegatedor:cachedfor bind mounts
- FastAPI Authentication with OIDC - Using Keycloak for authentication
- FastAPI Testing Strategy - Running integration tests
- FastAPI Temporal Workflows - Using Temporal in development