job-defaults
Inject shared default settings across every job at compile time.
Define default job-level settings once at the top level; Actio merges them into
every job at compile time and strips both job-defaults and executors from the
output — zero residual directives.
Both jobs inherit runs-on and timeout-minutes; env is deep-merged so lint
ends up with both CI and DEBUG:
name: CI
on: [push]
job-defaults:
runs-on: ubuntu-latest
timeout-minutes: 30
env:
CI: "true"
jobs:
test:
steps:
- run: npm test
lint:
env:
DEBUG: "1"
steps:
- run: npm run lintjobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 30
env:
CI: "true"
steps:
- run: npm test
lint:
runs-on: ubuntu-latest
timeout-minutes: 30
env:
CI: "true"
DEBUG: "1"
steps:
- run: npm run lintname: CI
on: [push]
job-defaults:
runs-on: ubuntu-latest
timeout-minutes: 30
env:
CI: "true"
jobs:
test:
steps:
- run: npm test
lint:
env:
DEBUG: "1"
steps:
- run: npm run lintjobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 30
env:
CI: "true"
steps:
- run: npm test
lint:
runs-on: ubuntu-latest
timeout-minutes: 30
env:
CI: "true"
DEBUG: "1"
steps:
- run: npm run lintMerge semantics
| Key | Behaviour |
|---|---|
if | AND-combined — default && inline. Never replaced. |
permissions, concurrency | Replace-on-presence — inline value wins entirely; default only applies when the key is absent. |
runs-on, timeout-minutes, continue-on-error, environment | Inline wins — job value takes precedence. |
env, container, services, defaults | Deep-merged — job keys overlay the default. |
strategy is intentionally per-job only. Put matrix and fail-fast settings on
each job so Actio does not silently turn per-job identity into a workflow-wide
default.
name: CI
on: [push]
job-defaults:
if: ${{ github.ref == 'refs/heads/main' }}
env:
REGION: us-east-1
jobs:
deploy:
runs-on: ubuntu-latest
if: ${{ success() }}
env:
REGION: eu-west-1
steps:
- run: ./deploy.shjobs:
deploy:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main' && success()
env:
REGION: eu-west-1
steps:
- run: ./deploy.shname: CI
on: [push]
job-defaults:
if: ${{ github.ref == 'refs/heads/main' }}
env:
REGION: us-east-1
jobs:
deploy:
runs-on: ubuntu-latest
if: ${{ success() }}
env:
REGION: eu-west-1
steps:
- run: ./deploy.shjobs:
deploy:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main' && success()
env:
REGION: eu-west-1
steps:
- run: ./deploy.shReusable-workflow call jobs
Jobs with uses: only receive the call-compatible subset of defaults: if,
permissions, and concurrency. Runner keys like runs-on, env, and
timeout-minutes are silently skipped (an info diagnostic is emitted listing
what was dropped). executor: is not supported on call jobs.
executors
Where job-defaults applies to every job, executors are named runner presets
a job opts into with executor: — for the cases where only some jobs need a
hardened runner, a container, or a service block. They share the same merge model
as job-defaults (inline job keys win) and compose left-to-right when listed.
See the dedicated executors page for the full guide.