Multi-project development environment manager - Start, stop, and monitor all your local development services from one place.
Working on multiple projects means juggling multiple terminals:
# Project A
cd ~/work/project-a && npm run dev # Terminal 1
cd ~/work/project-a && cargo run # Terminal 2
# Project B
cd ~/work/project-b && docker compose up # Terminal 3
cd ~/work/project-b && npm start # Terminal 4
# Which ports? Which commands? Where's that README again?devhub start project-a # Starts all services
devhub start project-b # Starts all services
devhub status # See everything at a glance
# Or open http://devhub.localhost for the dashboard- One command to rule them all -
devhub startlaunches your entire stack - Bulk discovery - Scan directories and register 100+ projects at once
- Monorepo support - Auto-detects multi-service projects (frontend + backend + packages)
- Environment file loading - Automatic
.envand.env.localsupport with variable interpolation - Web dashboard - Visual status, start/stop buttons, log viewer, real-time updates
- Fuzzy search - Find projects fast with
devhub search - Favorites & Recent - Star projects, track recently used
- Batch operations -
devhub start --allor--favorites - Auto-discovery - Detects Rust, Node, Python, Go, Docker, Flutter projects
- Port conflict detection - Know before you crash with
devhub ports --resolve - PM2 integration - Node.js services managed properly
- Docker Compose support - First-class container orchestration
- Health checks - Wait for services to be truly ready
- Reverse proxy integration - Pretty URLs like
http://myproject.localhost - Shell completions - Tab completion for bash, zsh, and fish
- Developer shortcuts -
devhub code,devhub open,devhub path - Zero lock-in - Simple TOML config, works with any stack
# Homebrew (macOS)
brew tap moinsen-dev/tap
brew install devhub
# Or download pre-built binary
curl -sL https://github.com/moinsen-dev/devhub/releases/latest/download/devhub-aarch64-apple-darwin.tar.gz | tar xz
sudo mv devhub /usr/local/bin/
# Or from source
git clone https://github.com/moinsen-dev/devhub.git && cd devhub
cargo build --release && cp target/release/devhub ~/.local/bin/# Scan your project directories
devhub scan --dry-run ~/work
# Found 50 projects? Register them all!
devhub scan --auto-register ~/work# Zsh (most common on macOS)
devhub completions zsh > ~/.zfunc/_devhub
# Bash
devhub completions bash > ~/.local/share/bash-completion/completions/devhub
# Fish
devhub completions fish > ~/.config/fish/completions/devhub.fish# Start a project
devhub start my-project
# Check status
devhub status
# Quick navigation
cd $(devhub path my-project) # Jump to project directory
devhub code my-project # Open in VS Code
devhub open my-project # Open in browser
# Check for port conflicts
devhub ports --check# Start the daemon as a background service
devhub daemon start
# Or if installed via Homebrew
brew services start devhub
# Start the UI
cd devhub-ui && npm install && npm run dev
# Open http://localhost:5173devhub init # Create devhub.toml in current directory
devhub discover # Auto-detect and generate devhub.toml
devhub discover --dry-run # Preview discovery without writing files
devhub register [path] # Register project with DevHub
devhub unregister <name> # Remove project from registry
devhub list # List all registered projectsdevhub scan [paths...] # Scan directories for projects
devhub scan --dry-run # Preview what would be discovered
devhub scan --auto-register # Discover and register in one step
devhub scan --depth 3 # Scan deeper into subdirectoriesdevhub start [project] # Start project services
devhub start --all # Start ALL registered projects
devhub start --favorites # Start all favorite projects
devhub stop [project] # Stop project services
devhub restart [project] # Restart project services
devhub status # Show status of all projects
devhub logs <project> [-f] # Stream logs (with follow mode)devhub search <query> # Fuzzy search for projects
devhub recent # Show recently used projects
devhub fav add <project> # Add to favorites
devhub fav list # List favorites
devhub fav toggle <project> # Toggle favorite statusdevhub ports # Show all port allocations
devhub ports --check # Detect port conflicts
devhub ports --resolve # Suggest fixes for conflictsdevhub open <project> # Open project in browser
devhub open <project> -s api # Open specific service
devhub code <project> # Open project in VS Code
devhub path <project> # Print project path (for cd integration)devhub env <project> # Show resolved environment variables
devhub env <project> -s api # Show env for specific service
devhub env <project> -f export # Output in shell export format
devhub completions <shell> # Generate shell completions (bash/zsh/fish)devhub daemon # Run daemon in foreground (default)
devhub daemon start # Start daemon as background service
devhub daemon stop # Stop running daemon
devhub daemon restart # Restart daemon
devhub daemon status # Show daemon status and version
devhub daemon --port 9876 # Run on custom portEach project gets a devhub.toml file:
[project]
name = "my-app"
description = "My awesome application"
tags = ["rust", "web"]
env_files = [".env", ".env.local"] # Environment files to load
[[services]]
name = "api"
type = "rust-binary"
command = "cargo run --release"
port = 8080
health_check = "/health"
subdomain = "api" # http://api.my-app.localhost
env_file = "api/.env" # Service-specific env file
[[services]]
name = "frontend"
type = "node"
command = "npm run dev"
cwd = "frontend" # Relative working directory
port = 3000
main = true # http://my-app.localhost (no subdomain)
depends_on = ["api"] # Start order
[environment]
RUST_LOG = "info"
DATABASE_URL = "postgres://localhost/myapp"Environment variables are loaded in this order (later sources override earlier):
- System environment variables
- Project root
.envfile - Project root
.env.localfile - Files listed in
env_files [environment]section in manifest- Service-specific
env_file - Service
cwd/.envfile - Service
cwd/.env.localfile - Service
env = {}section - DevHub service URL injection (see below)
Variable interpolation is supported: DATABASE_URL=$DB_HOST:$DB_PORT/mydb
DevHub automatically injects environment variables for service-to-service communication. This solves the common problem of hardcoding localhost:PORT in your .env files.
For every service in your project, DevHub injects:
| Variable | Example | Description |
|---|---|---|
DEVHUB_<SERVICE>_URL |
http://api.myapp.localhost |
External URL via Caddy reverse proxy |
DEVHUB_<SERVICE>_INTERNAL_URL |
http://myapp-api:8080 |
Internal URL for container-to-container |
DEVHUB_<SERVICE>_PORT |
8080 |
Service port |
Example for a project with api and frontend services:
DEVHUB_API_URL=http://api.myapp.localhost
DEVHUB_API_INTERNAL_URL=http://myapp-api:8080
DEVHUB_API_PORT=8080
DEVHUB_FRONTEND_URL=http://myapp.localhost
DEVHUB_FRONTEND_INTERNAL_URL=http://myapp-frontend:3000
DEVHUB_FRONTEND_PORT=3000You can reference other services in your devhub.toml using the ${service.property} syntax:
[[services]]
name = "frontend"
type = "node"
command = "npm run dev"
port = 3000
main = true
[services.env]
# These get auto-expanded by DevHub:
NEXT_PUBLIC_API_URL = "${api.url}" # → http://api.myapp.localhost
INTERNAL_API_URL = "${api.internal}" # → http://myapp-api:8080
API_PORT = "${api.port}" # → 8080Available properties:
${service.url}- External URL (via Caddy, for browser/client-side)${service.internal}- Internal URL (for container-to-container communication)${service.port}- Service port number
[project]
name = "demo-app"
mode = "container"
[[services]]
name = "backend"
type = "python"
command = "uvicorn main:app --host 0.0.0.0 --port 8081"
port = 8081
subdomain = "api"
[[services]]
name = "frontend"
type = "node"
command = "npm run dev"
port = 3000
main = true
[services.env]
# Client-side API calls go through Caddy
NEXT_PUBLIC_API_URL = "${backend.url}"Your frontend automatically gets NEXT_PUBLIC_API_URL=http://api.demo-app.localhost - no more hardcoded localhost:8081!
| Type | Detection | Default Command |
|---|---|---|
rust-binary |
Cargo.toml with [[bin]] |
cargo run |
node |
package.json |
npm run dev (uses PM2 if available) |
python |
pyproject.toml |
uvicorn or python -m |
go |
go.mod |
go run . |
docker-compose |
docker-compose.yml |
docker compose up -d |
shell |
Any | Custom command |
The web dashboard provides:
- Project cards with running status indicators
- One-click start/stop/restart buttons
- Log viewer with auto-refresh and syntax highlighting
- Service-level controls (start/stop individual services on hover)
- Real-time auto-refresh (5-second polling)
- Search and filter by name or status
- Service metrics (X/Y services running)
- Open in Terminal / VS Code buttons
Access:
http://devhub.localhost(with Caddy proxy)http://localhost:5173(development mode)
DevHub auto-generates Caddy configurations for pretty .localhost URLs.
cd proxy
docker compose up -dThis gives you:
http://projectname.localhost- Your main servicehttp://api.projectname.localhost- API serviceshttp://devhub.localhost- Dashboard
mkdir -p ~/.devhub
cat > ~/.devhub/config.toml << EOF
caddy_sites_dir = "/path/to/your/proxy/sites.d"
caddy_reload_command = "docker exec caddy-proxy caddy reload --config /etc/caddy/Caddyfile"
EOFdevhub/
├── src/ # Rust CLI + daemon
│ ├── main.rs # CLI entry (clap)
│ ├── api.rs # REST API (axum)
│ ├── process.rs # Service management (PM2, Docker, native)
│ ├── discovery.rs # Auto-detection (6 project types)
│ ├── manifest.rs # TOML parsing
│ ├── registry.rs # Project registry (+ favorites, recent)
│ ├── ports.rs # Port allocation & conflict detection
│ ├── caddy.rs # Proxy config generation
│ └── config.rs # Global settings
├── devhub-ui/ # SvelteKit dashboard (Svelte 5)
├── proxy/ # Caddy reverse proxy setup
└── Cargo.toml # Rust dependencies
DevHub checks both IPv4 and IPv6. If issues persist:
lsof -i :3000PM2 must be installed globally:
npm install -g pm2# Check logs
devhub logs my-project my-service
# Or directly
cat ~/Library/Application\ Support/com.moinsen.devhub/logs/my-project/my-service.err.logdocker exec caddy-proxy caddy reload --config /etc/caddy/Caddyfile
docker logs caddy-proxybrew tap moinsen-dev/tap
brew install devhub
# Start as background service (optional)
brew services start devhubDownload from GitHub Releases:
# macOS Apple Silicon
curl -sL https://github.com/moinsen-dev/devhub/releases/latest/download/devhub-aarch64-apple-darwin.tar.gz | tar xz
sudo mv devhub /usr/local/bin/
# macOS Intel
curl -sL https://github.com/moinsen-dev/devhub/releases/latest/download/devhub-x86_64-apple-darwin.tar.gz | tar xz
sudo mv devhub /usr/local/bin/
# Linux x64
curl -sL https://github.com/moinsen-dev/devhub/releases/latest/download/devhub-x86_64-unknown-linux-gnu.tar.gz | tar xz
sudo mv devhub /usr/local/bin/
# Linux ARM64
curl -sL https://github.com/moinsen-dev/devhub/releases/latest/download/devhub-aarch64-unknown-linux-gnu.tar.gz | tar xz
sudo mv devhub /usr/local/bin/git clone https://github.com/moinsen-dev/devhub.git
cd devhub
cargo build --release
cp target/release/devhub ~/.local/bin/cargo install devhubContributions welcome! See CONTRIBUTING.md for guidelines.
MIT License - see LICENSE for details.
- Caddy - The reverse proxy that makes this possible
- axum - Excellent Rust web framework
- clap - CLI argument parsing with completions
- PM2 - Node.js process management
- SvelteKit - Clean, fast UI framework
"Stop remembering. Start building."