Configuration
deck uses a deck.yaml file at the project root. Run deck init to generate one.
Full example
name: myproject
# Global environment variables — injected into all commands.
env:
PGPASSWORD: postgres
PG_HOST: 127.0.0.1
# External dependencies the stack needs running.
deps:
postgres:
check: pg_isready -h 127.0.0.1
start:
- docker run -d --name postgres -p 5432:5432 -e POSTGRES_PASSWORD=postgres postgres:16
- brew services start postgresql@16
stop:
- docker stop postgres && docker rm postgres
- brew services stop postgresql@16
# One-time setup tasks. Only run if check fails.
bootstrap:
- name: Install deps
dir: ./webapp
check: test -d node_modules
run: pnpm install
- name: Create database
env:
PG_HOST:
file: "api/etc/app.conf | db.host"
PG_USER:
file: "api/etc/app.conf | db.user"
check: psql -h $PG_HOST -U $PG_USER -d myapp -c 'SELECT 1' 2>/dev/null
run: createdb -h $PG_HOST -U $PG_USER myapp
- name: Set auth key
check: "! grep -q \"AUTH_KEY=''\" .env"
prompt: |
Paste the PEM public key from your auth provider.
Press Enter on an empty line when done.
run: ./scripts/set-auth-key.sh "$DECK_INPUT_FILE"
# Lifecycle hooks.
hooks:
pre-start:
- name: Run migrations
dir: ./api
env_file: ./etc/app.env
run: goose up
post-stop: []
# Services to manage.
services:
api:
dir: ./api
run: go run ./cmd/server
port: 4000
color: cyan
env_file: ./etc/app.env
env:
NO_COLOR: "1"
ready: curl -sf http://localhost:4000/healthz
webapp:
dir: ./webapp
run: pnpm dev
port: 5173
color: magenta
depends_on: [api]
Config fields
| Field | Where | Description |
|---|---|---|
env | top-level, service, bootstrap, hook | Env vars — string, $(…) interpolation, or object with value/script/file. |
env_file | service, hook, bootstrap | Path to a dotenv file loaded before running. |
dir | service, bootstrap, hook | Working directory for the command. |
check | dep, bootstrap | Shell command — exit 0 means “already done, skip”. |
start/stop | dep | String or list of strategies tried in order. |
prompt | bootstrap | Interactive multi-line prompt. Input available as $DECK_INPUT and $DECK_INPUT_FILE. |
color | service | Log prefix color (cyan, magenta, yellow, green, blue, red). Auto-assigned if omitted. |
timestamp | service | Inject timestamps into log lines (default true, auto-detects existing timestamps). |
depends_on | service | List of services that must start (and be ready) first. |
ready | service | Shell command polled after start — exit 0 means ready. Blocks dependents. |
restart | service | Restart policy: always, on-failure, or omit for no restart. Active during deck up. |
port | service | For status display only. |
Env var syntax
Env vars can be a plain string or an object:
env:
# Plain string
NO_COLOR: "1"
# Shell interpolation (legacy syntax, still supported)
PG_HOST: "$(grep host config.ini | cut -d= -f2)"
# Explicit script — stdout becomes the value
PG_HOST:
script: "grep host config.ini | cut -d= -f2"
# Read from structured file — supports .json, .yaml, .toml, .conf/.ini
PG_HOST:
file: "api/etc/app.conf | db.host"
# Static value (same as plain string)
PG_PORT:
value: "5432"
The file format is path | key.path where the key path uses dots to traverse nested sections. For INI/conf files, section headers become the first key level: [db] + host = localhost is db.host.
Service dependencies
Services support depends_on for ordered startup and ready for readiness gating:
services:
api:
run: go run ./cmd/server
port: 4000
ready: curl -sf http://localhost:4000/healthz
webapp:
run: pnpm dev
depends_on: [api]
- Services start in topological order (dependencies first)
- Cycles are detected at config parse time
readyis polled every 500ms with a 30s timeout- Selective targeting auto-expands to include transitive dependencies
Crash recovery
Services can be automatically restarted when they crash during deck up:
services:
api:
run: go run ./cmd/server
restart: on-failure # or "always"
always— restart on any exiton-failure— restart only on non-zero exit code- Omit or leave empty for no restart (default)
The watch loop checks every 2 seconds.
Local overrides
Create deck.local.yaml (gitignored) to override team defaults:
deps:
postgres:
start:
- brew services start postgresql@16
Maps merge by key (preserving order), lists replace entirely.
Custom config file
deck up -f staging.yaml # no local merge