Services
Services
Services are long-running processes that Trellis manages throughout your development session.
Service Definition
Define services in your trellis.hjson:
{
services: [
{
// Required: unique name
name: "backend"
// Command to run (string or array)
command: "./bin/backend"
// or: command: ["./bin/backend", "-port", "8080"]
// Working directory (default: worktree root)
work_dir: "{{.Worktree.Root}}/services/backend"
// Environment variables
env: {
DB_HOST: "localhost"
DEBUG: "true"
}
// Binary to watch for changes (auto-restart on change)
watch_binary: "{{.Worktree.Binaries}}/backend"
// Additional files to watch (configs, etc.)
watch_files: [
"config/backend.yaml"
"config/database.yaml"
]
// Enable/disable the service (default: enabled)
enabled: true
// disabled: true // Alternative way to disable
// Include in binary watching (default: true)
// Set to false for external services like databases
watching: true
}
]
}
When Services Start
Services start automatically when Trellis launches, unless disabled. Here’s the startup sequence:
- On Trellis launch: All enabled services (
enabled: true, the default) start immediately - On worktree activation: When you switch worktrees, all services stop and restart in the new worktree’s context
- On binary change: When a watched binary changes, only that service restarts
Services with enabled: false or disabled: true won’t start automatically but can be started manually via the UI or trellis-ctl start <name>.
Service Lifecycle
States
| State | Description |
|---|---|
stopped |
Not running |
starting |
Process started |
running |
Running |
stopping |
Graceful shutdown in progress |
crashed |
Exited unexpectedly |
State Transitions
stopped → starting → running → stopping → stopped
↓ ↓
crashed crashed
Binary and File Watching
Trellis can automatically restart services when files change. There are three related settings:
watch_binary
The primary mechanism for auto-restart. When the specified binary file changes, the service restarts:
{
name: "backend"
command: "./bin/backend"
watch_binary: "./bin/backend" // Restart when this file changes
}
watch_files
Additional files to watch beyond the binary. Useful for config files:
{
name: "backend"
command: "./bin/backend"
watch_binary: "./bin/backend"
watch_files: ["config.yaml", "secrets.env"] // Also restart on these
}
Both watch_binary and watch_files trigger restarts independently—a change to any watched file restarts the service.
watching: false
Excludes a service from the binary watching system entirely. Use this for external services (databases, third-party tools) that you don’t build:
{
name: "redis"
command: ["redis-server"]
watching: false // Never auto-restart, even if watch_binary is set
}
When watching: false, the service won’t restart when binaries change, even if watch_binary is configured. The service still starts on Trellis launch and can be controlled manually.
Debounce
File watchers use debouncing to avoid rapid restarts during builds:
{
watch: {
debounce: "100ms" // Wait for rapid changes to settle (default)
}
}
The restart sequence:
- You recompile:
go build -o ./bin/backend ./cmd/backend - Trellis detects the binary changed
- Debounce timer starts (waits for additional changes)
- After debounce period, the service is gracefully stopped (SIGTERM)
- The service restarts
- A
binary.changedevent is emitted
Restart Policies
Control what happens when a service exits:
{
services: [
{
name: "worker"
command: "./bin/worker"
restart_policy: "on-failure" // "always", "on-failure", "never"
max_restarts: 3 // Give up after N attempts
restart_delay: "1s" // Wait between restarts
}
]
}
Alternatively, use a nested restart block with just the policy:
{
services: [
{
name: "worker"
command: "./bin/worker"
restart: {
policy: "on-failure"
}
max_restarts: 3
restart_delay: "1s"
}
]
}
Crash Reports
When a service crashes, Trellis captures:
- Recent log lines (context before the crash)
- Exit code
- Stack trace (if configured)
- Timestamp and worktree context
View crashes with:
trellis-ctl crash newest
trellis-ctl crash list
Service Log Tracing
Services with logging.parser configured (directly or via logging_defaults) are automatically registered as trace-searchable log sources. Trellis creates svc:<name> log viewers backed by each service’s in-memory ring buffer and collects them into a services trace group:
# Search all service log buffers for a trace ID
trellis-ctl trace "req-123" services -since 1h
# View available trace groups
trellis-ctl trace-report -groups
This enables distributed tracing across dev services with zero configuration. Two-pass ID expansion works when the service parser includes an id field (e.g., id: "request_id").
Service Events
Services emit events throughout their lifecycle:
| Event | Description |
|---|---|
service.started |
Service started running |
service.stopped |
Service stopped |
service.crashed |
Service exited unexpectedly |
service.restarted |
Service was restarted |
binary.changed |
Watched binary was modified |