# Stacks Development

> Use when setting up or configuring the Stacks development environment - dev server, hot reload, development utilities, or IDE configuration. Covers the @stacksjs/development package, the dev server, CLI commands, reverse proxy, SSL, and dev workflow.

- Skill: `stacksjs/stacks-development` (Agent Skill)
- Install (CLI): `npx skillmds@latest add stacksjs/stacks-development`
- Raw SKILL.md: https://api.skillmd.com/api/skills/stacksjs/stacks-development/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Productivity
- License: MIT
- Author: stacksjs (https://skillmd.com/u/stacksjs)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/stacksjs/stacks-development

---


# Stacks Development

## Key Paths
- Development package: `storage/framework/core/development/` (stub — exports `{}`)
- Dev server entry: `storage/framework/server/src/index.ts`
- Dev server utils: `storage/framework/server/src/utils.ts`
- Server build script: `storage/framework/server/build.ts`
- Dev action handlers: `storage/framework/core/actions/src/dev/`
- Buddy CLI dev commands: `storage/framework/core/buddy/src/commands/dev.ts`
- Preloader: `storage/framework/defaults/resources/plugins/preloader.ts`
- Port config: `config/ports.ts`
- STX config: `config/ui.ts`
- IDE defaults: `storage/framework/defaults/ide/`
- SSL setup: `storage/framework/core/actions/src/setup/ssl.ts`
- Bun config: `bunfig.toml`
- Dockerfile: `storage/framework/server/Dockerfile`

## Source Files
```
actions/src/dev/
├── index.ts            # Re-exports all run*DevServer() wrappers
├── api.ts              # API dev server (bun-router with CORS, port from config.ports.api)
├── views.ts            # Frontend dev server (bun-plugin-stx serve, .stx templates)
├── dashboard.ts        # Dashboard dev server (STX + native Craft window + config API)
├── dashboard-utils.ts  # Model discovery, sidebar config, icon map, waitForServer()
├── docs.ts             # Docs dev server (@stacksjs/bunpress, watch mode)
├── components.ts       # Components dev server (runs `bun run dev` in libs/components/vue)
├── desktop.ts          # Desktop dev server (runs `bun run dev` in framework/views/desktop)
└── system-tray.ts      # System tray dev server (runs `bun run dev` in framework/system-tray)

server/
├── src/
│   ├── index.ts        # Production server entry (Bun.serve, WebSocket, queue worker mode)
│   └── utils.ts        # cleanCopy(), useCustomOrDefaultServerConfig(), buildDockerImage()
├── build.ts            # Server build script (Bun.build for ESM, Docker image)
├── dev                 # Shell script for running server via Docker with volume mounts
├── Dockerfile          # Multi-stage build: oven/bun:1.3.10, exposes port 3000
├── package.json        # stacks-server package
├── tsconfig.docker.json
└── tsconfig.json

buddy/src/commands/
├── dev.ts              # All `buddy dev` subcommands
├── build.ts            # All `buddy build` subcommands
├── setup.ts            # `buddy setup` and `buddy setup:ssl`
├── doctor.ts           # `buddy doctor` health checks
└── maintenance.ts      # `buddy down`, `buddy up`, `buddy status`
```

## Port Configuration (config/ports.ts)

```typescript
{
  frontend: env.PORT ?? 3000,
  backend: env.PORT_BACKEND ?? 3001,
  admin: env.PORT_ADMIN ?? 3002,
  library: env.PORT_LIBRARY ?? 3003,
  desktop: env.PORT_DESKTOP ?? 3004,
  email: env.PORT_EMAIL ?? 3005,
  docs: env.PORT_DOCS ?? 3006,
  inspect: env.PORT_INSPECT ?? 3007,
  api: env.PORT_API ?? 3008,
  systemTray: env.PORT_SYSTEM_TRAY ?? 3009,
  database: 3010,
}
```

## CLI Commands

### Dev Server Commands
- `buddy dev` -- Start ALL dev servers in parallel (frontend, API, docs, dashboard + reverse proxy if custom domain)
- `buddy dev [server]` -- Start a specific server: `frontend`, `api`, `components`, `dashboard`, `desktop`, `system-tray`, `docs`
- `buddy dev -i` / `--interactive` -- Interactive prompt to choose which server to start
- `buddy dev --browser` -- Override a configured native launch and open the browser app
- `buddy dev --site` -- Open the marketing site instead of the app or native window
- `buddy dev --verbose` -- Show detailed output including proxy info and dependency logs
- `buddy dev:frontend` (aliases: `dev:pages`, `dev:views`) -- Frontend only
- `buddy dev:api` -- API server only
- `buddy dev:dashboard` (alias: `dev:admin`) -- Dashboard with native Craft window
- `buddy dev:docs` -- Documentation server only
- `buddy dev:components` -- Vue component library dev server
- `buddy dev:desktop` -- Desktop app dev server
- `buddy dev:native` -- Equivalent native app development flow
- `buddy dev:system-tray` (alias: `dev:tray`) -- System tray dev server

### Build Commands
- `buddy build` -- Build stacks framework (default when no option specified)
- `buddy build components` -- Build component libraries
- `buddy build docs` -- Build documentation site
- `buddy build server` (alias: `build:docker`) -- Build Docker server image
- `buddy build:core` -- Build Stacks core packages
- `buddy build:stacks` -- Build the full Stacks framework
- `buddy build:cli` -- Build Buddy CLI binary

### Setup & Maintenance
- `buddy setup` (alias: `ensure`) -- Full project setup (pantry, deps, config)
- `buddy setup:ssl` (alias: `ssl:setup`) -- Generate and trust SSL certs for custom domain
- `buddy doctor` -- Health checks (Bun version, Node.js, package.json, .env, APP_KEY)
- `buddy fresh` -- Clean project + reinstall dependencies
- `buddy clean` -- Remove build artifacts via `cleanProject()`
- `buddy down` -- Maintenance mode (supports `--message`, `--secret`, `--retry`, `--allow`)
- `buddy up` -- Exit maintenance mode
- `buddy status` -- Check maintenance mode status

## Dev Server Architecture

### Unified Dev Server (`buddy dev` with no arguments)
When `buddy dev` runs without a specific server flag, `startDevelopmentServer()` in `dev.ts`:
1. Reads `config/app.ts` `devLaunch`; `native` opens `appPath` in Craft, while `browser` keeps the browser default
2. Reads port configuration from env vars (`PORT`, `PORT_API`, `PORT_DOCS`, `PORT_ADMIN`)
3. Detects custom domain from `APP_URL` (e.g., `stacks.localhost`)
4. Prints Vite-style banner with URLs for Frontend, API, Docs, Dashboard
5. Sets `STACKS_PROXY_MANAGED=1` to prevent subprocesses from starting their own proxies
6. Starts all servers in parallel via `Promise.all()`:
   - `runFrontendDevServer()` -- STX template server on port 3000
   - `runApiDevServer()` -- bun-router API on port 3008
   - `runDocsDevServer()` -- bunpress docs on port 3006
   - `runDashboardDevServer()` -- STX + Craft native window on port 3002
   - `startReverseProxy()` -- rpx HTTPS proxy on port 443 (only if custom domain set)
7. Registers SIGINT/SIGTERM handlers that `SIGKILL` the entire process group

### Action Execution (`runAction` in helpers/utils.ts)
- Dev actions (paths starting with `dev/`) automatically get `--watch` flag via `bun --watch`
- The `dev/views` action is special-cased for maximum performance: imports `bun-plugin-stx/serve` directly instead of spawning a subprocess
- `NODE_PATH` is set to include `pantry/` so compiled pantry packages can resolve `@stacksjs/*` at runtime
- Dev action subprocess output is suppressed by default (quiet mode), visible with `--verbose`

### Frontend Dev Server (views.ts)
Uses `bun-plugin-stx` serve function with pattern-based view resolution:
- User views: `resources/views` (checked first)
- Default views: `storage/framework/defaults/resources/views` (fallback)
- User layouts: `resources/layouts`
- Default layouts: `storage/framework/defaults/resources/layouts`
- Components: `storage/framework/defaults/resources/components/Dashboard`

### API Dev Server (api.ts)
- Uses `@stacksjs/router` with CORS middleware
- Calls `route.importRoutes()` to load route definitions
- Serves on `127.0.0.1` at `config.ports.api` (default 3008)

### Dashboard Dev Server (dashboard.ts)
- Starts the STX server on `config.ports.admin` and optionally opens a native Craft window
- Mounts the config API on the same dashboard origin under `/api/config/*`
- Config routes list, read, expose source for, and atomically update `config/*.ts` files
- Config updates support top-level scalar literals only and preserve comments and environment-backed expressions
- Discovers ORM models from `app/Models/` and `storage/framework/defaults/app/Models/`
- Writes `.discovered-models.json` manifest for sidebar population
- Preloads ORM model globals for server scripts, while framework server helpers use explicit imports
- Leaves `resources/functions` to the STX client auto-import pipeline because browser helpers may depend on signals and other browser-only primitives
- Opens a Craft `createApp()` window when a supported SDK and native binary are available (1400x900, titlebar hidden)
- Builds the web sidebar from configured sections and discovered model dashboard metadata

### Docs Dev Server (docs.ts)
- Uses `@stacksjs/bunpress` with `{ watch: true, quiet: true }`
- Serves from `docs/` directory on port 3006

## Reverse Proxy & HTTPS

When `APP_URL` is set to a custom domain (not `localhost`):
- `startReverseProxy()` uses `@stacksjs/rpx` to proxy all subdomains through HTTPS on port 443
- Proxy mapping: `localhost:3000 -> domain`, `localhost:3008 -> api.domain`, `localhost:3006 -> docs.domain`, `localhost:3002 -> dashboard.domain`
- SSL certs stored in `~/.stacks/ssl/` with 825-day validity
- Individual dev servers check `STACKS_PROXY_MANAGED` to avoid starting duplicate proxies

### SSL Setup (`setup/ssl.ts`)
- `setupSSL(options)` -- Complete SSL setup: hosts file + cert generation + trust
- `generateCertificates(domain)` -- Uses `@stacksjs/tlsx` to create Root CA + host cert
- `addDomainToHosts(domain)` -- Adds `127.0.0.1 <domain>` to `/etc/hosts` (requires sudo)
- `trustCertificate(domain)` -- Adds cert to macOS Keychain or Linux ca-certificates
- Supports non-interactive mode via `SUDO_PASSWORD` env var
- Cert files: `~/.stacks/ssl/<domain>.crt`, `<domain>.key`, `<domain>.ca.crt`

## Hot Reload / Watch Mode

- **Dev actions use `bun --watch`**: All actions with paths starting with `dev/` are automatically run with Bun's `--watch` flag, which restarts the process on file changes
- **Frontend (STX)**: `bun-plugin-stx/serve` has its own built-in watch/HMR for `.stx` templates
- **API server**: Runs via `bun --watch`, restarts on route or handler changes
- **Docs**: `@stacksjs/bunpress` runs with `watch: true` for live documentation updates
- **Components**: Delegates to the component library's own `bun run dev` (typically Vite-based HMR)

## Preloader (preloader.ts)

Configured in `bunfig.toml` as `preload = ["./storage/framework/defaults/resources/plugins/preloader.ts"]`.

### Execution Phases
1. **Fast command skip**: Commands like `dev`, `build`, `test`, `lint`, `--version`, `--help` skip the preloader entirely for maximum startup speed
2. **Environment detection**: Deploy/production commands (`deploy`, `cloud:remove`, etc.) set `APP_ENV` and `NODE_ENV` before loading env files
3. **Env loading**: Calls `autoLoadEnv({ quiet: true })` from `@stacksjs/env` for encrypted `.env` file support
4. **Auto-imports** (non-fast commands only):
   - Loads 21 `@stacksjs/*` packages into `globalThis` (actions, router, orm, validation, etc.)
   - Loads all functions from `resources/functions/**/*.ts`
   - Loads all ORM model instances into `globalThis` (priority: user > framework > defaults)
   - Loads all Job instances from `app/Jobs/` into `globalThis`
   - Loads all Controller classes into `globalThis`
   - Runs `discoverPackages()` for package auto-discovery
5. **Protected globals**: 80+ built-in names (process, console, Buffer, fetch, Bun, etc.) are never overwritten

### bunfig.toml Configuration
```toml
preload = ["./storage/framework/defaults/resources/plugins/preloader.ts"]

[test]
preload = ["./tests/setup.ts"]
coverage = true

[run]
bun = true  # equivalent to `bun --bun` for all `bun run` commands

[serve.static]
plugins = ["bun-plugin-stx"]  # STX template engine plugin for Bun.serve

[install]
registry = { url = "https://registry.npmjs.org/", token = "$BUN_AUTH_TOKEN" }
linker = "hoisted"
```

## Production Server (server/src/index.ts)

- **Queue worker mode**: When `QUEUE_WORKER` env var is set, imports and runs the job from `app/Jobs/<JOB>.ts` with retry support (configurable via `JOB_RETRIES`, `JOB_BACKOFF_FACTOR`, `JOB_INITIAL_DELAY`, `JOB_JITTER`)
- **HTTP server**: `Bun.serve()` on `PORT` (default 3000), delegates to `serverResponse()` from `@stacksjs/router`
- **WebSocket**: Built-in WebSocket upgrade support (open/message/close handlers as stubs)
- **Development mode**: Auto-enabled when `APP_ENV` is not `production` or `prod`
- **Docker**: Multi-stage build with `oven/bun:1.3.10`, runs as non-root `bun` user, exposes port 3000, includes curl for healthchecks

## Server Build Process (server/build.ts)

1. Stops any running `stacks-server` Docker container
2. Cleans previous build artifacts (app/, config/, dist/, docs/, storage/)
3. Builds server entry (`src/index.ts`) to `dist/` using `Bun.build` (ESM, target: bun)
4. Builds all `app/**/*.{ts,js}` files to `server/app/` (ESM, no splitting, external: `@swc/wasm`)
5. Post-processes built files: rewrites `storage/framework/server` imports to `dist/`
6. Strips `export { ENV_KEY, ENV_SECRET, fromEnv }` from dist (bundler workaround)
7. Copies custom server config if present (`server/` dir at project root)
8. Optionally builds Docker image if `cloud.api.deploy` is enabled

## IDE Support

Default configurations provided at `storage/framework/defaults/ide/`:

### Cursor
- `cursor/rules/`: 11 rule files (auto-imports, code-style, documentation, error-handling, key-conventions, project-structure, syntax-formatting, testing, typescript, ui-styling, readme)

### VS Code
- `vscode/.vscode/extensions.json` -- Recommended extensions
- `vscode/.vscode/settings.json` -- Editor settings
- `vscode/.vscode/stacks.code-snippets` -- Code snippets
- `vscode/package.json` -- VS Code extension manifest

### JetBrains
- `.idea/` config (ESLint, modules, VCS, web resources)
- `.fleet/settings.json` -- Fleet IDE settings
- `options/` (GitHub Copilot, Node.js config)
- `templates/` (JavaScript and Stacks live templates)

### Zed
- `zed/.zed/settings.json` -- Zed editor settings

### Dictionary
- `dictionary.txt` -- Custom spell-check dictionary

## Doctor Health Checks

`buddy doctor` verifies:
- Bun runtime version (pass if v1.0+, warn otherwise, fail if missing)
- Node.js version (pass if v18+, warn otherwise)
- package.json existence and project name
- `.env` file presence (warn if missing, not a failure)
- `APP_KEY` is set (warn if not, suggests `buddy key:generate`)

## STX Configuration (config/ui.ts)

```typescript
{
  componentsDir: 'components',
  layoutsDir: 'layouts',
  partialsDir: 'partials',
}
```

Note: Dashboard mode overrides these settings via its own `serve()` options.

## Gotchas
- The `@stacksjs/development` package is currently a stub (`export {}`) -- all actual dev tooling lives in the actions and server packages
- The preloader skips entirely for `dev`, `build`, `test`, `lint`, and version/help commands -- auto-imports are NOT available in those contexts
- `buddy dev` (no arguments) starts ALL servers simultaneously -- use `buddy dev api` or `buddy dev frontend` to start only one
- The `STACKS_PROXY_MANAGED=1` env var prevents individual dev servers from starting their own reverse proxy -- only the unified `buddy dev` command manages the proxy
- Dev actions are executed with `bun --watch` automatically -- do NOT add `--watch` manually or you get double-restart behavior
- The `dev/views` action is special-cased in `runAction()` to run in-process (no subprocess) for performance -- other dev actions spawn subprocesses
- `NODE_PATH` is injected to include `pantry/` directory so compiled pantry packages can resolve `@stacksjs/*` dependencies at runtime
- The dashboard config API shares the dashboard origin and atomically modifies top-level scalar literals in `config/*.ts`. Nested values, arrays, and environment-backed expressions remain read-only.
- SSL certificates are stored in `~/.stacks/ssl/`, NOT in the project directory -- they persist across projects using the same domain
- Custom server configuration in `server/` at the project root overrides the default server config via file copy (checked by `useCustomOrDefaultServerConfig()`)
- The production server doubles as a queue worker when `QUEUE_WORKER` env var is set -- it imports the job by name from `app/Jobs/` and exits after completion
- Docker build strips `src/` directories, test files, sourcemaps, and `node_modules` from the image to minimize size
- The `bun-plugin-stx` serve plugin is resolved with a fallback: first tries normal `import('bun-plugin-stx/serve')`, then falls back to `pantry/bun-plugin-stx/dist/serve.js`
- `buddy fresh` is NOT the same as `buddy clean` -- `fresh` cleans AND reinstalls dependencies, while `clean` only removes artifacts
- The Craft native window for the dashboard uses `http://localhost:<port>` directly (not HTTPS) even when a custom domain proxy is running

