Includes

Split your task file into multiple files across subdirectories. Each included directory must contain its own gogo.yaml.

Basic Setup

project/
├── gogo.yaml
├── backend/
│   └── gogo.yaml
└── frontend/
    └── gogo.yaml
# project/gogo.yaml
includes:
  - backend
  - frontend
# project/backend/gogo.yaml
tasks:
  build:
    cmd: go build ./...

  test:
    cmd: go test ./...

Namespaced Tasks

Included tasks are prefixed with their directory name:

gogo backend:build
gogo frontend:test

Namespace Defaults

An included file can declare its own default: task:

# project/backend/gogo.yaml
default: dev

tasks:
  dev:
    cmd: go run ./cmd/server

Invoking the exact namespace runs that default:

gogo backend    # runs backend:dev

An exact task or alias still takes precedence over a namespace default. Defaults are preserved at every include depth, so gogo services:api can run the default declared by services/api/gogo.yaml.

References Between Included Tasks

Task references are relative to the file that declares them. References to local tasks and nested includes are automatically qualified when the file is loaded under a namespace:

# project/services/gogo.yaml
includes:
  - api

tasks:
  deploy:
    deps: [api:build]
    cmds:
      - task: api:test

From the project root, those references resolve to services:api:build and services:api:test. The same file therefore works both directly from services/ and when included by the project root.

Automatic Namespace Resolution

When you run gogo from a subdirectory, it automatically resolves task names to the matching namespace. From the backend/ directory:

cd backend
gogo build      # resolves to backend:build

Wildcard Patterns

A ... wildcard runs a same-named task across every namespace (Bazel-style):

gogo ...:test     # runs test, backend:test, frontend:test, ...

The wildcard spans zero or more namespace levels, so nested tasks like a:b:test match too. Namespaces without a matching task are skipped; the pattern errors only when nothing matches at all. Matching is exact (no prefix shortcuts or aliases) and internal _-prefixed tasks are never included. Matches run in parallel and all of them run even if one fails.

When run from a subdirectory, the pattern is scoped to that namespace’s subtree — gogo ...:test from backend/ only runs tasks under backend:.

Patterns are accepted anywhere a task name is: in deps: (matches run in parallel) and in task: sub-calls (matches run in sequence). The one exception is --watch, which needs a single task to poll and rejects patterns.

Dotenv Deduplication

Each included task file can define its own dotenv files. If multiple includes reference the same .env file (by absolute path), it’s loaded only once.

Flatten

flatten is a sibling of includes for splitting a single namespace across multiple YAML files. Where includes adds a directory whose tasks become namespaced (backend:build), flatten pulls another YAML file’s tasks into the current namespace verbatim:

# gogo.yaml
flatten:
  - tasks/lint.yml
  - tasks/test.yml

tasks:
  default:
    deps: [lint, test]
# tasks/lint.yml
tasks:
  lint:
    cmd: golangci-lint run
# tasks/test.yml
tasks:
  test:
    cmd: go test ./...
gogo lint    # no namespace prefix
gogo test

Key behaviors:

Edit this page on GitHub