Skip to main content

Docker Dev Setup

Run the complete Open Saasframe stack โ€” app, PostgreSQL, Redis, and Meilisearch โ€” inside Docker with hot reload. Every file change is picked up automatically. No local Node.js, Yarn, or native build tools are required.

When to use this

This setup works on any OS. On Windows, it is slower than the native monorepo flow because bind-mounted file watching crosses the Windows/WSL filesystem boundary. Prefer the native path for day-to-day Windows development.


Prerequisitesโ€‹

  • Docker Desktop โ€” Windows ยท macOS ยท Linux
  • Docker Compose v2+ (bundled with Docker Desktop)
  • Git โ€” Windows ยท macOS: xcode-select --install ยท Linux: sudo apt install git
  • At least 4 GB RAM allocated to Docker (Docker Desktop โ†’ Settings โ†’ Resources)
Windows-specific
  • Enable the WSL 2 backend in Docker Desktop (Settings โ†’ General โ†’ "Use the WSL 2 based engine").
  • Clone with CRLF handling disabled to avoid line-ending issues in shell scripts:
    git config --global core.autocrlf input

Quick startโ€‹

git clone https://github.com/saasframe/saasframe.git
cd saasframe
git checkout develop

# Optional: customise environment before first run
cp apps/saasframe/.env.example apps/saasframe/.env

# Build and start the full dev stack
docker compose -f docker-compose.fullapp.dev.yml up --build

The first run takes several minutes โ€” Docker builds the image, installs dependencies, builds packages, applies migrations, and seeds demo data. Subsequent starts are much faster because initialisation is cached in a named volume.

Once the runtime is ready, open:

  • Splash / startup progress: http://localhost:4000
  • Backend: http://localhost:3000/backend

Sign in with the default credentials printed during initialisation (typically [email protected] / the password shown in the logs).


How it worksโ€‹

The docker-compose.fullapp.dev.yml stack runs five services:

ServiceImagePurpose
appBuilt from Dockerfile (dev stage)Next.js app with hot reload
postgrespgvector/pgvector:pg17-trixiePostgreSQL 17 with pgvector
redisredis:7-alpineCaching and event persistence
meilisearchgetmeili/meilisearch:v1.11Full-text search
opencodeCustomClaude Code integration (optional)

The app container:

  • Mounts your source code from the host into /app
  • Uses named volumes for node_modules, .next, and package dist/ so the container manages its own builds
  • Enables file-watching via polling (CHOKIDAR_USEPOLLING, WATCHPACK_POLLING) for reliable change detection on all platforms
  • On first run executes yarn saasframe init; on subsequent runs applies pending migrations only

Common operationsโ€‹

# Start in detached mode (background)
docker compose -f docker-compose.fullapp.dev.yml up -d

# View logs โ€” all services
docker compose -f docker-compose.fullapp.dev.yml logs -f

# View logs โ€” app only
docker compose -f docker-compose.fullapp.dev.yml logs -f app

# Rebuild after pulling new commits
docker compose -f docker-compose.fullapp.dev.yml up --build

# Stop all services
docker compose -f docker-compose.fullapp.dev.yml down

# Full reset โ€” deletes all data and cached builds
docker compose -f docker-compose.fullapp.dev.yml down -v
docker compose -f docker-compose.fullapp.dev.yml up --build

Docker wrapper commandsโ€‹

The repository exposes yarn docker:* commands that run the equivalent workflow inside the running app container โ€” so you don't need to type docker compose exec ... manually.

Start the dev stack first:

yarn docker:dev:up

Then run monorepo workflows from the host:

yarn docker:build:packages
yarn docker:generate
yarn docker:initialize
yarn docker:initialize -- --reinstall
yarn docker:db:migrate
yarn docker:lint
yarn docker:typecheck
yarn docker:test

Restart the app service and tail logs:

yarn docker:dev

# Skip the install/build/generate phase (faster restart):
yarn docker:dev -- --skip-rebuilt

Environment variablesโ€‹

All variables are pre-configured with sensible defaults in the compose file. Override them in apps/saasframe/.env before starting.

VariableDefaultDescription
APP_PORT3000Host port for the app
SF_DEV_SPLASH_PORT4000Host port for the startup splash page
SF_DEV_AUTO_OPEN1Set to 0 to disable browser auto-open
POSTGRES_PASSWORDpostgresDatabase password
JWT_SECRETJWTAuth token secret โ€” change for production
OPENAI_API_KEYโ€”Enables OpenAI-backed AI features; combine it with SF_DISABLE_VECTOR_SEARCH_AUTOINDEXING=false to turn vector auto-indexing on
SF_DISABLE_VECTOR_SEARCH_AUTOINDEXINGtrue in the shipped example envSet to false or remove it to enable automatic vector indexing
DEMO_MODEtrueSeeds demo CRM data on first run

Vector auto-indexing is disabled by default in apps/saasframe/.env.example. To enable it, configure an embedding provider such as OPENAI_API_KEY and set SF_DISABLE_VECTOR_SEARCH_AUTOINDEXING=false before you start the stack. The legacy alias DISABLE_VECTOR_SEARCH_AUTOINDEXING=1 is still honored for older deployments.


Troubleshootingโ€‹

Container fails to start on Windows:

  • Ensure WSL 2 backend is enabled in Docker Desktop.
  • Verify the repo was cloned with core.autocrlf=input to avoid CRLF issues in shell scripts.
  • Allocate at least 4 GB RAM to Docker (Docker Desktop โ†’ Settings โ†’ Resources).

File changes not detected: The compose file sets polling by default. If changes are still not picked up:

docker compose -f docker-compose.fullapp.dev.yml restart app

Port conflicts:

# Change app port
APP_PORT=3001 docker compose -f docker-compose.fullapp.dev.yml up

# Change splash port
SF_DEV_SPLASH_PORT=4100 docker compose -f docker-compose.fullapp.dev.yml up

# Change Postgres port (when localhost:5432 is occupied)
POSTGRES_PORT=55432 docker compose -f docker-compose.fullapp.dev.yml up
# And update DATABASE_URL in .env to match

Slow file watching on Windows/WSL 2: Store the repository inside the WSL 2 filesystem (\\wsl$\Ubuntu\home\...) rather than on the Windows filesystem (/mnt/c/...) for significantly better I/O performance.