How to Deploy Thunderbolt Using Docker Compose: Complete Setup Guide
Thunderbolt deploys as a multi-container stack using the deploy/docker-compose.yml file in the thunderbird/thunderbolt repository, which orchestrates React/Vite frontend, Bun backend, PostgreSQL, MongoDB, PowerSync, and Keycloak services with a single docker compose up --build command.
Thunderbolt is a full-stack web application from the thunderbird organization that requires multiple services running in concert. Deploying Thunderbolt using Docker Compose provides a reproducible, containerized environment for local development or production testing without manual configuration of individual components.
Architecture Overview
Thunderbolt consists of seven containerized services defined in deploy/docker-compose.yml. The frontend builds a static Vite bundle served via Nginx, while the backend runs a Node.js/Bun API server that handles database migrations on startup. Supporting infrastructure includes PostgreSQL for relational data, MongoDB replica sets for PowerSync document storage, the PowerSync real-time sync service, and an embedded Keycloak instance for OIDC authentication.
Key Configuration Files
All deployment configurations reside in the deploy/ directory at the repository root:
| File | Purpose |
|---|---|
deploy/docker-compose.yml |
Orchestrates all services and networking |
deploy/docker/frontend.Dockerfile |
Multi-stage build for React/Vite + Nginx |
deploy/docker/backend.Dockerfile |
Bun-based API server image |
deploy/docker/backend-entrypoint.sh |
Entrypoint script that runs bun drizzle-kit migrate before starting the server |
config/powersync-config.yaml |
PowerSync sync rules and table configurations |
config/keycloak-realm.json |
Pre-configured Keycloak realm with clients and users |
Step-by-Step Deployment Guide
1. Clone the Repository
git clone https://github.com/thunderbird/thunderbolt.git
cd thunderbolt
2. Configure Environment Variables
Create a .env file in the project root (or copy from .env.example). At minimum, define secrets required by the backend and Keycloak:
# Example .env
BETTER_AUTH_SECRET=your-secret-key
POSTGRES_PASSWORD=secure-postgres-password
KEYCLOAK_ADMIN_PASSWORD=admin-password
3. Launch the Stack
Run the full stack with image builds:
docker compose -f deploy/docker-compose.yml up --build -d
The --build flag compiles the frontend and backend images from their respective Dockerfiles. The -d flag detaches the containers.
4. Verify Health Checks
Wait 30-60 seconds for all services to initialize. Check logs to confirm successful startup:
docker compose -f deploy/docker-compose.yml logs -f
Look for "Server started" messages from the backend and "ready for connections" from PostgreSQL and MongoDB.
5. Access the Application
| Service | URL | Default Port |
|---|---|---|
| Frontend UI | http://localhost:3000 |
${FRONTEND_PORT:-3000} |
| Backend API | http://localhost:8000/v1 |
${BACKEND_PORT:-8000} |
| Keycloak Admin | http://localhost:8180/admin |
${KEYCLOAK_PORT:-8180} (default login: admin/admin) |
6. Shut Down
To stop and remove all containers and volumes:
docker compose -f deploy/docker-compose.yml down -v
The -v flag deletes persistent data in pg_data and mongo_data volumes.
Custom Integration Examples
When integrating Thunderbolt into an existing Docker Compose stack, reference pre-built images rather than building from source:
version: "3.9"
services:
thunderbolt:
image: thunderbolt/backend:latest
ports:
- "8000:8000"
env_file: .env
environment:
DATABASE_URL: postgresql://postgres:postgres@postgres:5432/postgres
POWERSYNC_URL: http://powersync:8080
depends_on:
- postgres
- powersync
postgres:
image: postgres:18-alpine
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: postgres
volumes:
- pg_data:/var/lib/postgresql/data
powersync:
image: journeyapps/powersync-service:latest
environment:
POWERSYNC_CONFIG_PATH: /config/config.yaml
volumes:
- ./config/powersync-config.yaml:/config/config.yaml
volumes:
pg_data:
Managing Migrations and Updates
The backend automatically runs database migrations on startup via deploy/docker/backend-entrypoint.sh, which executes bun drizzle-kit migrate. To run migrations manually (for example, after pulling updates):
docker compose -f deploy/docker-compose.yml run --rm backend bun drizzle-kit migrate
For updates, pull the latest code, rebuild images, and restart:
git pull origin main
docker compose -f deploy/docker-compose.yml up --build -d
Summary
- Thunderbolt deploys via the
deploy/docker-compose.ymlfile in the thunderbird/thunderbolt repository, which orchestrates seven containerized services. - The stack includes a React/Vite frontend, Bun backend, PostgreSQL, MongoDB replica set, PowerSync, and Keycloak.
- Deploy by cloning the repo, creating a
.envfile, and runningdocker compose -f deploy/docker-compose.yml up --build -d. - The backend entrypoint at
deploy/docker/backend-entrypoint.shhandles database migrations automatically usingbun drizzle-kit migrate. - Access the frontend on port 3000, backend API on port 8000, and Keycloak admin on port 8180 by default.
Frequently Asked Questions
What ports does Thunderbolt expose by default?
By default, the Docker Compose configuration exposes the frontend on port 3000, the backend API on port 8000, and Keycloak on port 8180. These can be customized by setting the FRONTEND_PORT, BACKEND_PORT, and KEYCLOAK_PORT environment variables in your .env file before launching the stack.
How do I run database migrations manually?
While the deploy/docker/backend-entrypoint.sh script automatically runs bun drizzle-kit migrate on container startup, you can execute migrations manually using docker compose run. This is useful for debugging or after updating the database schema: docker compose -f deploy/docker-compose.yml run --rm backend bun drizzle-kit migrate.
Can I use an existing PostgreSQL instance instead of the container?
Yes. To use an external PostgreSQL database, remove the postgres service from your custom Compose file and set the DATABASE_URL environment variable to point to your existing instance (e.g., postgresql://username:password@hostname:5432/database). Ensure network connectivity between the Thunderbolt backend container and your external database host.
How do I customize the PowerSync configuration?
PowerSync behavior is controlled by the config/powersync-config.yaml file mounted into the PowerSync container. Modify this file to define sync rules, table mappings, and filtering logic before deployment. The Docker Compose file mounts this configuration at /config/config.yaml inside the powersync service container, and the POWERSYNC_CONFIG_PATH environment variable points to this location.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →