executors
Named runner presets — extract repeated runner, container, and service config into reusable templates.
job-defaults applies one set of defaults to every
job. executors is the opt-in companion: named presets that a job pulls in by name
with executor:. Use it when some jobs need a hardened runner, a container, or a
service block and others don't — define the preset once, reference it where it
applies. Both executors and the executor: key are stripped from the output.
name: CI
on: [push]
executors:
hardened:
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
contents: read
jobs:
test:
executor: hardened
steps:
- run: npm testname: CI
on:
- push
jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
contents: read
steps:
- run: npm testname: CI
on: [push]
executors:
hardened:
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
contents: read
jobs:
test:
executor: hardened
steps:
- run: npm testname: CI
on:
- push
jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
contents: read
steps:
- run: npm testComposing executors
executor: accepts an ordered list of names. Presets are merged left-to-right, so
later entries win for scalar keys and env-style maps are deep-merged:
jobs:
build:
executor: [base, gpu]
steps:
- run: ./build.shAn inline runner key on the job always wins over what the executor provides, so a job can adopt a preset and still override one field locally.
Gotchas
Precedence
Within a job the resolution order is: job-defaults (lowest) → executor
presets (left-to-right) → inline job keys (highest). The most specific value
wins.
Not supported on call jobs
executor: is not supported on reusable-workflow call jobs (uses:), which only
accept the call-compatible subset of defaults. See the
job-defaults callout for what call jobs inherit.
See the executors and executor
entries in the syntax reference for the full preset and composition rules.