Workflows
Workflows
Workflows are parameterized commands you can run from the Trellis web UI or CLI. They turn common tasks — builds, deploys, database operations, test runs — into repeatable actions with input dialogs, confirmation prompts, and structured output.
Defining a Workflow
Define workflows in your trellis.hjson:
{
workflows: [
{
id: "build"
name: "Build All"
command: ["make", "build"]
}
]
}
Every workflow needs an id (used in the CLI and URLs), a name (shown in the UI), and either command or commands.
Single vs. Multi-Command
Use command for a single command:
{
id: "test"
name: "Run Tests"
command: ["go", "test", "-json", "-count=1", "./..."]
}
Use commands to run multiple commands sequentially. If any command fails, the remaining commands are skipped:
{
id: "db-reset"
name: "Reset Database"
commands: [
["./bin/dbutil", "reset"]
["./bin/dbutil", "seed"]
]
}
Template Variables
Commands support Go template variables for worktree-aware paths:
{
id: "build"
name: "Build"
command: ["make", "-C", "{{.Worktree.Root}}", "build"]
}
See Template Variables for the full list.
Inputs
Workflows can prompt the user for input before execution. Inputs appear as a dialog in the web UI or as --flag=value arguments in the CLI.
Input Types
text — Free-form text entry:
{
name: "version"
type: "text"
label: "Version Tag"
placeholder: "e.g., v1.2.3"
pattern: "^v[0-9]+\\.[0-9]+\\.[0-9]+$"
required: true
}
select — Dropdown with predefined options:
{
name: "environment"
type: "select"
label: "Target Environment"
options: ["staging", "production"]
default: "staging"
required: true
}
checkbox — Boolean toggle:
{
name: "dry_run"
type: "checkbox"
label: "Dry run (don't actually deploy)"
default: false
}
datepicker — Date selector (defaults to today if no default specified):
{
name: "deploy_date"
type: "datepicker"
label: "Deploy Date"
}
Using Inputs in Commands
Reference input values in commands and confirmation messages with {{ .Inputs.<name> }}:
{
id: "deploy"
name: "Deploy"
inputs: [
{ name: "env", type: "select", options: ["staging", "prod"], required: true }
{ name: "dry_run", type: "checkbox", label: "Dry run", default: false }
]
command: [
"./deploy.sh"
"--env={{ .Inputs.env }}"
"{{ if .Inputs.dry_run }}--dry-run{{ end }}"
]
}
Validation
Text inputs support two validation mechanisms:
| Field | Description |
|---|---|
pattern |
Regex that the value must match |
allowed_values |
Whitelist of acceptable values |
Invalid inputs are rejected before the workflow runs, both in the web UI and CLI.
Confirmation
Require the user to confirm before a workflow runs:
{
id: "db-reset"
name: "Reset Database"
confirm: true
confirm_message: "This will delete all data. Continue?"
commands: [
["./bin/dbutil", "reset"]
["./bin/dbutil", "seed"]
]
}
The confirm_message field supports templates, so you can include input values:
confirm_message: "Deploy to {{ .Inputs.environment }}?"
Output Parsers
The output_parser field controls how Trellis displays workflow output:
| Parser | Description |
|---|---|
go |
Parses Go compiler output. File:line references become clickable links to your editor. |
go_test_json |
Parses go test -json output. Shows pass/fail/skip status per test with timing. |
generic |
Line-by-line output with exit code summary. The default if no parser is specified. |
html |
Renders the output as HTML in the browser. Useful for formatted reports. |
none |
Suppresses output display entirely. |
Example with go_test_json:
{
id: "test"
name: "Run Tests"
command: ["go", "test", "-json", "-count=1", "./..."]
output_parser: "go_test_json"
timeout: "10m"
}
Structured Summary
When an output parser is configured, completed runs also carry a Summary rollup in the status API: error and warning counts, test pass/fail/skip counts, the names of failing tests, and the first error message. This gives programmatic consumers — trellis-ctl -json, the Go client, and AI agents validating their changes — pass/fail detail without re-parsing the raw output. Summary is null for workflows without a parser.
Service Coordination
Workflows can interact with services:
requires_stopped — Stop specific services before the workflow runs, then restart them afterward:
{
id: "migrate"
name: "Run Migrations"
command: ["./bin/migrate", "up"]
requires_stopped: ["api", "worker"]
}
restart_services — Restart all watched services after the workflow completes (useful for build workflows):
{
id: "build"
name: "Build All"
command: ["make", "build"]
restart_services: true
}
Timeouts
Set a maximum duration with the timeout field. If the workflow exceeds the timeout, the process is killed:
{
id: "test"
name: "Run Tests"
command: ["go", "test", "./..."]
timeout: "10m"
}
Values use Go duration syntax: "30s", "5m", "1h".
Running Workflows
Web UI
Open the workflow picker from the navbar or press Cmd/Ctrl + /. Select a workflow to run it. If the workflow has inputs, a dialog prompts you to fill them in. Output is displayed in a dedicated view with the configured parser.
CLI
# List available workflows
trellis-ctl workflow list
# See a workflow's inputs and validation rules
trellis-ctl workflow describe deploy
# Run a workflow (waits for completion)
trellis-ctl workflow run build
# Run with inputs
trellis-ctl workflow run deploy --environment=staging --dry_run=true
# Check status of a running workflow (pass the run ID, not workflow ID)
trellis-ctl workflow status <run-id>
# Cancel a running workflow (pass a run ID, or a workflow ID to cancel
# its most recent in-flight run)
trellis-ctl workflow cancel <id>
Examples
Build Workflow
A simple build that restarts services afterward:
{
id: "build"
name: "Build All"
command: ["make", "build"]
output_parser: "go"
timeout: "10m"
restart_services: true
}
Deploy Workflow
Inputs, confirmation, and service coordination:
{
id: "deploy"
name: "Deploy"
inputs: [
{ name: "environment", type: "select", label: "Environment", options: ["staging", "production"], default: "staging", required: true }
{ name: "deploy_date", type: "datepicker", label: "Deploy Date" }
{ name: "dry_run", type: "checkbox", label: "Dry run", default: false }
]
confirm: true
confirm_message: "Deploy to {{ .Inputs.environment }}?"
command: ["./deploy.sh", "--env={{ .Inputs.environment }}", "--date={{ .Inputs.deploy_date }}", "{{ if .Inputs.dry_run }}--dry-run{{ end }}"]
requires_stopped: ["api", "worker"]
timeout: "15m"
}
Database Query Workflow
Text inputs with HTML output:
{
id: "db-fetch"
name: "DB Fetch"
description: "Fetch a database row by table and ID"
inputs: [
{ name: "table", type: "text", label: "Table", placeholder: "e.g., users", required: true }
{ name: "id", type: "text", label: "Row ID", placeholder: "e.g., 12345", pattern: "^[0-9]+$", required: true }
]
command: ["./bin/dbutil", "fetch", "--table={{ .Inputs.table }}", "--id={{ .Inputs.id }}", "--format=html"]
output_parser: "html"
}