Skip to main content

Monorepo β€” Core Development

Use this guide when you want to contribute to the Open Saasframe core, work on platform features, or run a full demo of the platform. If you want to build a product app without touching the core, use the Standalone App guide instead.

Prerequisites​

Install the following tools before continuing. Each step includes a verification command.

1. Git​

macOS may already have Git via Xcode Command Line Tools. Check with git --version. If it is missing, install the CLT:

xcode-select --install

Or install Git via Homebrew (see next step).

2. Homebrew​

If Homebrew is not already installed:

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

Follow the post-install instructions printed by the script to add Homebrew to your shell PATH.

3. Node.js 26​

# Option A β€” Homebrew
brew install node@26
echo 'export PATH="/opt/homebrew/opt/node@26/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc

# Option B β€” nvm (manage multiple Node versions)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.0/install.sh | bash
# Close and reopen your terminal, then:
nvm install 26
nvm use 26
nvm alias default 26

Verify: node --version β†’ v24.x.x

4. Yarn 4.12.0​

Corepack ships with Node.js. Enable it once per machine, then activate Yarn:

corepack enable
corepack prepare yarn@4.12.0 --activate

Verify: yarn --version β†’ 4.12.0

5. Docker Desktop​

Download and install Docker Desktop for Mac. Start it after installation.

Verify:

docker --version
docker compose version

Infrastructure services​

Docker Desktop runs PostgreSQL, Redis, and Meilisearch. Start them from the repository root after cloning (step below):

docker compose up -d

This starts:

  • PostgreSQL 17 with the pgvector extension β€” port 5432
  • Redis 7 β€” port 6379
  • Meilisearch β€” port 7700

Clone and configure​

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

Copy the environment template:

cp apps/saasframe/.env.example apps/saasframe/.env

Edit apps/saasframe/.env and set at least these three variables:

DATABASE_URL=postgres://postgres:postgres@localhost:5432/saasframe
JWT_SECRET=change-me-dev-secret
REDIS_URL=redis://localhost:6379

Generate a strong JWT_SECRET:

openssl rand -hex 32

Install dependencies and bootstrap​

yarn install

yarn build:packages
yarn generate
yarn build:packages # second run required β€” compiles generated scripts

yarn initialize

yarn initialize runs migrations, seeds roles, provisions an admin user, and loads demo CRM data. Add --no-examples to skip demo content. The admin credentials are printed at the end.


Start the app​

yarn dev

Open http://localhost:3000/backend and sign in with the credentials printed by yarn initialize.

The compact runtime also serves a splash page at http://localhost:4000 with live startup progress. Press d while yarn dev is running to toggle raw log output.

On memory-constrained machines you can lower yarn dev's footprint by narrowing which workspace packages the watcher tracks with SF_WATCH_SCOPE (e.g. SF_WATCH_SCOPE=auto-optimized yarn dev). The active mode is printed with an emoji at startup. See Choosing which packages the watcher tracks for the full reference.


Upgrading an existing checkout​

git pull
yarn install
yarn db:migrate
yarn generate
yarn dev

Development runtime reference​

CommandDescription
yarn devCompact runtime β€” splash at http://localhost:4000, app at http://localhost:3000/backend
yarn dev:verboseSame runtime with raw passthrough logs
yarn dev:greenfieldFull fresh boot: build β†’ generate β†’ reinstall β†’ dev
yarn dev:ephemeralThrowaway database on a random port (requires Docker)
yarn dev:classicLegacy mode β€” disables splash, raw output

Press d while yarn dev is running to toggle raw log output. If a stage fails, the runner automatically expands and prints the raw error.

Run multiple persistent local instances against the same PostgreSQL server​

yarn dev, yarn dev:greenfield, and yarn dev:app accept an optional --database-name[=<name>] flag that rewrites the database segment of DATABASE_URL in apps/saasframe/.env. Without the flag, behavior is unchanged.

# explicit name; you'll be asked once whether to persist .env (default yes)
yarn dev:greenfield --database-name=pricing_v2

# bare flag derives the database name from the current working directory
yarn dev --database-name

# one-off review run that does not edit .env
yarn dev --database-name=review_1720 --no-update-env

The override only touches the pathname segment of DATABASE_URL, so credentials, host, port, schema (?schema=…), and other query parameters are preserved. CI / non-interactive runs default to updating .env; pass --no-update-env to opt out, or set SF_DEV_DATABASE_UPDATE_ENV=false.