Skip to main content

Local Development Guide

This guide covers setting up DaoFlow for local development, testing the CLI, and running the Next.js example app.

Prerequisites

1. Clone and Install

git clone https://github.com/DaoFlow-dev/DaoFlow.git
cd DaoFlow
bun install

2. Start Infrastructure

DaoFlow uses Postgres and Redis (via Docker) plus Temporal (via native CLI):

# Start Postgres + Redis
bun run dev:infra

# Start Temporal dev server (separate terminal)
bun run dev:temporal

This starts:

ServicePortSourceDescription
postgres5432DockerDaoFlow primary database (pgvector)
redis6379DockerBackground job queue + SSE streaming
temporal7233CLI (native)Temporal workflow engine
Temporal UI8233CLI (native)Temporal web dashboard

Note: Temporal runs natively via temporal server start-dev with built-in SQLite — no Docker needed. Install with brew install temporal.

Or start everything at once:

bun run dev:full

bun run dev:full enables Temporal-backed deployment dispatch automatically for the server process.

3. Initialize the Database

Push the Drizzle schema to Postgres:

bun run db:push

4. Start the Development Server

bun run dev

The DaoFlow server runs at http://localhost:3000.

4.5 Run E2E Against The Same Dev Stack

Playwright E2E reuses the same docker-compose.dev.yml services used for local development. The E2E scripts bring the stack up if needed, reset dedicated E2E databases, push the current schema, seed test data, and then start the app on the host for browser tests.

bun run test:e2e

5. Create a Test User

Open http://localhost:3000 in a browser and sign up with an email and password. The first user gets the owner role.


Testing the CLI Locally

Build the CLI

The CLI uses bun workspace to share types with the server via @daoflow/server/router:

bun build packages/cli/src/index.ts --outfile dist/daoflow --target bun

Login

# Sign in with email/password (captures session cookie from Better Auth)
bun dist/daoflow login --url http://localhost:3000 --email you@example.com --password yourpassword

Run Commands

# Identity & permissions
bun dist/daoflow whoami --json
bun dist/daoflow capabilities --json

# Infrastructure health
bun dist/daoflow status --json
bun dist/daoflow doctor --json

# Services & projects
bun dist/daoflow services --json
bun dist/daoflow projects list --json

# Deployment (dry-run, exit code 3)
bun dist/daoflow deploy --service svc_my_svc --dry-run --json

# Backups
bun dist/daoflow backup list --json
bun dist/daoflow backup run --policy <id> --dry-run
bun dist/daoflow backup restore --backup-run-id <id> --dry-run

Develop Without Rebuilding

During active CLI development, run directly from source with bun run:

bun run packages/cli/src/index.ts whoami --json
bun run packages/cli/src/index.ts services --json

This uses bun's native TypeScript execution — no build step needed. Changes to CLI source files take effect immediately.

tRPC Type Safety

The CLI uses a vanilla @trpc/client with the shared AppRouter type from the server:

@daoflow/server/router  ──→  exports AppRouter type
↓ (bun workspace:*)
packages/cli/src/trpc-client.ts ──→ createTRPCClient<AppRouter>

All CLI commands ──→ trpc.*.query() / trpc.*.mutate()

If you add a new tRPC procedure on the server, the CLI gets full type inference automatically.


Testing the Example App

Next.js Example

The repo includes a ready-to-deploy Next.js app:

cd examples/nextjs-daoflow-example

# Install dependencies
bun install

# Run locally (port 3001)
bun run dev

Open http://localhost:3001 to verify the app works.

Build and Run with Docker

cd examples/nextjs-daoflow-example

# Build the Docker image
docker build -t nextjs-daoflow-example .

# Run it
docker run -p 3001:3000 nextjs-daoflow-example

Deploy via CLI (to local DaoFlow)

# Service deploy (dry-run first)
bun dist/daoflow deploy --service svc_nextjs_example --dry-run --json

# When ready (requires deploy:start scope)
bun dist/daoflow deploy --service svc_nextjs_example --yes

Compose Deploy with Local Context

For projects using Docker Compose with build.context: ., use the compose deploy flow:

cd examples/nextjs-docker-compose-example

# Preview the deployment plan
bun dist/daoflow deploy --compose ./compose.yaml --server srv_local_dev --dry-run

# Execute the deployment
bun dist/daoflow deploy --compose ./compose.yaml --server srv_local_dev --yes

Ignore Files

DaoFlow respects both .dockerignore and .daoflowignore:

FilePurpose
.dockerignoreStandard Docker ignore rules (e.g., node_modules, .git)
.daoflowignoreDaoFlow-specific overrides — lines starting with ! force-include files excluded by .dockerignore (e.g., !.env)

Both files are applied in order: .dockerignore first, then .daoflowignore as additive overrides.

Configuration (daoflow.config.*)

Create a daoflow.config.jsonc (or .json, .yaml, .toml) for deployment defaults:

{
"$schema": "https://raw.githubusercontent.com/DaoFlow-dev/DaoFlow/main/packages/cli/daoflow.config.schema.json",
"project": "my-app",
"server": "production",
"compose": "compose.yaml",
"context": ".",
"include": [".env"], // force-include (overrides .dockerignore)
"maxContextSize": "500mb" // safety limit
}

See examples/nextjs-docker-compose-example/ for full samples in JSONC, YAML, and TOML.


Project Structure

DaoFlow/
├── packages/
│ ├── server/ # API + tRPC router + Drizzle ORM
│ ├── client/ # React web UI
│ ├── cli/ # CLI (uses @trpc/client + bun workspace)
│ └── shared/ # Shared types and constants
├── docker-compose.dev.yml # Local dev: Postgres + Redis (Docker)
├── docker-compose.yml # Production: GHCR images + .env secrets
├── temporal-config/ # Temporal dynamic config (production)
└── examples/
├── nextjs-daoflow-example/ # Sample app (image deploy)
└── nextjs-docker-compose-example/ # Sample app (compose + local context)

Useful Commands

CommandDescription
bun installInstall all workspace dependencies
bun run devStart DaoFlow server + client
bun run dev:infraStart Postgres + Redis (Docker)
bun run dev:temporalStart Temporal CLI dev server
bun run dev:fullStart entire stack at once
bun run db:pushPush Drizzle schema to Postgres
bun run typecheckType-check all packages
bun run lintRun ESLint across the monorepo
bun run test:e2eRun Playwright E2E tests
bun run test:e2e:workerRun worker E2E tests (requires Temporal)
docker compose -f docker-compose.dev.yml downStop Docker infrastructure