Actio
Macros

templates

Parameterized, named step lists spliced into jobs with inject … with.

_anchors reuses a step list verbatim — but the moment the sequence differs by a value (a Node version, a deploy target, an environment name) anchors can't help: YAML anchors take no arguments. templates: defines a named, typed step list and splices it into a job with - inject: <name> plus a with: mapping. {{ args.<name> }} references in the body resolve at compile time; both the templates key and the inject call are erased from the output.

.actio.yml
name: Deploy
on: [push]
templates:
  deploy:
    params:
      env: { type: string }
      url: { type: string }
    steps:
      - run: ./deploy.sh --env {{ args.env }}
      - run: curl -sf {{ args.url }}/health
jobs:
  staging:
    runs-on: ubuntu-latest
    steps:
      - inject: deploy
        with: { env: staging, url: https://staging.example.com }
  prod:
    runs-on: ubuntu-latest
    steps:
      - inject: deploy
        with: { env: prod, url: https://example.com }
generated .yml
jobs:
  staging:
    runs-on: ubuntu-latest
    steps:
      - run: ./deploy.sh --env staging
      - run: curl -sf https://staging.example.com/health
  prod:
    runs-on: ubuntu-latest
    steps:
      - run: ./deploy.sh --env prod
      - run: curl -sf https://example.com/health
.actio.yml
name: Deploy
on: [push]
templates:
  deploy:
    params:
      env: { type: string }
      url: { type: string }
    steps:
      - run: ./deploy.sh --env {{ args.env }}
      - run: curl -sf {{ args.url }}/health
jobs:
  staging:
    runs-on: ubuntu-latest
    steps:
      - inject: deploy
        with: { env: staging, url: https://staging.example.com }
  prod:
    runs-on: ubuntu-latest
    steps:
      - inject: deploy
        with: { env: prod, url: https://example.com }
generated .yml
jobs:
  staging:
    runs-on: ubuntu-latest
    steps:
      - run: ./deploy.sh --env staging
      - run: curl -sf https://staging.example.com/health
  prod:
    runs-on: ubuntu-latest
    steps:
      - run: ./deploy.sh --env prod
      - run: curl -sf https://example.com/health

Param types reuse the params type system (string, number, boolean, enum, defaults, required).

Cross-file templates

inject also pulls a template from another file with inject: ./path#name, so a team can keep a shared library of step sequences in one place. Define #setup once in a shared lib.actio.yml and inject it from any source file:

ci.actio.yml
lib.actio.yml
ci.actio.yml
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - inject: ./.github/actio/lib.actio.yml#setup
      - run: npm test

When to use templates vs _anchors vs call-templates

You needUse
Same step list, no parameters, same file_anchors — native YAML, zero macro surface
A step list that varies by a value, or lives in another filetemplates: — typed params: + inject … with
Reuse the plumbing of a reusable-workflow call job (uses/with/needs/secrets)call-templates — job-level extends:

templates: splices steps into a job; call-templates templates an entire call job. They do not overlap.

See the canonical templates entry for the full keyword contract.

On this page