Skip to content

Local Development Setup

Two modes are available. The Docker Stack is recommended for day-to-day development.

ModeCommandBest for
Docker Stack (recommended)pnpm run dev:stack:upDay-to-day development
Infra-Only + Host Appspnpm run dev:infra:up + pnpm run devNative debugging, macOS without VirtioFS

One-Time Setup

1. Prerequisites

macOS: Docker Desktop required. After installing, enable VirtioFS for fast hot reload:

Docker Desktop → Settings → General → "Use Virtualization framework" → Apply & Restart

VirtioFS on macOS

Without VirtioFS, file-watching inside Docker containers is noticeably slow. Hot reload will work but feel laggy. Check this setting before proceeding.

Linux: Docker Engine + Docker Compose plugin. No extra settings required.

Windows: Use WSL2 with Docker Desktop's WSL integration. Clone and run the repository inside the WSL2 filesystem; native Windows development is not supported.

2. Copy environment files

bash
cp apps/server/.env.example    apps/server/.env
cp apps/webapp/.env.example    apps/webapp/.env
cp apps/marketing/.env.example apps/marketing/.env

apps/webapp/.env and apps/marketing/.env are pre-filled — no changes needed.

For apps/server/.env, fill in the following values:

VariableHow to get it
APP_KEYcd apps/server && node ace generate:key
BETTER_AUTH_SECRETcd apps/server && node ace generate:key
HEALTH_SECRETcd apps/server && node ace generate:key
REDIS_PASSWORDFrom 1Password vault
RESEND_API_KEYFrom 1Password vault
BREVO_API_KEYFrom 1Password vault

Docker Stack overrides DB/Redis hosts

DB_HOST and REDIS_HOST are automatically overridden inside the stack. You only need to set the secrets above.

3. Set up HTTPS certificates

bash
cd infra/local_dev
chmod +x setup-https.sh
./setup-https.sh

What the script does:

  1. Installs mkcert (if not present)
  2. Installs a local CA into your system trust store (may prompt for your password)
  3. Generates infra/local_dev/certs/local.cert.pem and certs/local.key.pem, covering jubiloop.localhost and *.jubiloop.localhost
  4. Linux only: adds /etc/hosts entries for all five domains (macOS resolves *.localhost automatically — no /etc/hosts changes needed)

Run once in each worktree that runs Docker

The certificate files are gitignored and bind-mounted from the active worktree. A new worktree does not receive them from Git, so run setup-https.sh there or copy the existing certs/ directory before starting its stack. The trusted mkcert CA is machine-wide and normally needs installation only once.


Starting up

bash
# Start in background (recommended)
pnpm run dev:stack:up

# Start in foreground (see all logs in terminal)
pnpm run dev:stack

First run: ~2–3 minutes to download images, install dependencies, and build shared packages. Subsequent starts are near-instant unless pnpm-lock.yaml changed.

What starts automatically

ServiceWhat it does
installRuns pnpm install --frozen-lockfile if lockfile changed, then builds shared-types and auth-client. Exits when done.
postgresPostgreSQL 15 on port 5433
redisRedis 7 on port 6379
serverRuns node ace migration:run --force then pnpm run dev with HMR
webappVite dev server with HMR
marketingNext.js dev server with Fast Refresh
ui-prototypeVite dev server for the design prototype (React 18 mock-data sandbox)
packagestsup --watch for auth-client and shared-types
docsVitePress dev server
caddyHTTPS reverse proxy

Migrations run automatically on every stack start (via node ace migration:run --force in the server container's startup command).

Local URLs

AppURL
Web App (React)https://app.jubiloop.localhost
API (AdonisJS)https://api.jubiloop.localhost
Marketing (Next.js)https://jubiloop.localhost
UI Prototypehttps://lab.jubiloop.localhost
Docs (VitePress)https://docs.jubiloop.localhost

Daily commands

bash
pnpm run dev:stack:up      # Start in background
pnpm run dev:stack:down    # Stop all containers
pnpm run dev:stack:logs    # Stream logs
pnpm run dev:stack:restart # Restart existing containers; does not switch worktree bind mounts
pnpm run dev:stack:rebuild-deps # Reinstall dependencies while preserving database data
pnpm run dev:stack:rebuild # Rebuild images and delete all local volumes and data

Switching worktrees

All worktrees use the same Compose project, container names, and named PostgreSQL, Redis, and node_modules volumes. Only one full stack can run at a time, and its data is shared. restart does not update source bind mounts. From the currently active worktree run pnpm run dev:stack:down, then run pnpm run dev:stack:up in the destination worktree so Docker recreates the containers with that worktree's paths. Use dev:stack:rebuild-deps if dependency versions differ. Do not use dev:stack:rebuild unless deleting the shared local data is intended.

Running commands inside the stack

bash
# Run tests
docker exec -it jubiloop_dev_server node ace test
docker exec -it jubiloop_dev_server node ace test --suite unit
docker exec -it jubiloop_dev_server node ace test --suite functional

# Database
docker exec -it jubiloop_dev_server node ace migration:run
docker exec -it jubiloop_dev_server node ace repl

# Access databases directly
docker exec -it jubiloop_dev_postgres psql -U postgres -d jubiloop_dev_db
docker exec -it jubiloop_dev_redis redis-cli

Container names (Docker Stack)

ServiceContainer name
postgresjubiloop_dev_postgres
redisjubiloop_dev_redis
installjubiloop_dev_install
serverjubiloop_dev_server
webappjubiloop_dev_webapp
marketingjubiloop_dev_marketing
ui-prototypejubiloop_dev_ui_prototype
packagesjubiloop_dev_packages
docsjubiloop_dev_docs
caddyjubiloop_dev_caddy

Dev TUI Dashboard

The Dev TUI is an optional interactive terminal dashboard for managing the local dev environment without memorising Docker commands.

bash
./dev-tui.sh        # from repo root
pnpm run dev:tui     # via pnpm

The script auto-builds a Go binary on first launch (no Go required — Docker is used as a fallback builder). The built binary lives at infra/local_dev/bin/dev-tui (gitignored) and is auto-rebuilt whenever source files change.

What the TUI provides

SectionFeatures
ServicesStart/stop full stack or infra-only, restart individual services, tail logs, shell into any container, open URLs in browser
Server & DatabaseRun migrations, seed or reset local data, open the backend REPL, run setup:dev
ConnectionsOpen psql shell, Redis CLI, copy DB connection URL to clipboard
Code QualityLint, lint-fix, format, run tests, build, type-check, security audit
MaintenanceRebuild containers, install dependencies, clear Turbo cache, wipe volumes, run HTTPS cert setup

Key features:

  • Real-time health monitoring: Docker container status + HTTP health checks every 5 seconds
  • Docker/Local execution mode toggle (Tab) — runs commands inside containers or directly on host
  • Fuzzy command search (/) across all 32 menu items
  • Scrollable output viewer for lint, test, and migration results
  • Persistent preferences (.tui-state.json, gitignored)

For full keyboard shortcuts, press ? inside the TUI.


Alternative: Infra-Only + Host Apps

See Host-Mode Development. Use this when:

  • Native debugging with Node.js inspector
  • macOS without VirtioFS enabled
  • Running Japa tests directly on the host

Service Reference

ServiceHost portDocker Stack containerInfra-only container
PostgreSQL5433jubiloop_dev_postgresjubiloop_local_dev_postgres
Redis6379jubiloop_dev_redisjubiloop_local_dev_redis
Caddy80, 443jubiloop_dev_caddyjubiloop_local_dev_caddy_proxy

Container names differ between modes

Docker Stack uses jubiloop_dev_*. Infra-only uses jubiloop_local_dev_*. Use the right name in docker exec commands.


Troubleshooting

Use the Troubleshooting guide for logs, port and certificate diagnostics, dependency recovery, and local database reset procedures.


Next: Git Worktrees for parallel development across branches

Built with ❤️ by the Jubiloop team