jobs
jobs:
Top-level map of jobs that run in parallel by default. Each job has an ID (used by `needs:` and outputs) and either a `steps:` list or a `uses:` reference to a reusable workflow.
jobs:
<job_id>:
runs-on: <runner>
steps: [...] Common values / subkeys
| Value / Subkey | Purpose |
|---|---|
| <job_id> | Unique key; must start with a letter or _ and contain only alphanumerics/-/_ |
| name | Human-readable display name (overrides the job_id in the UI) |
| runs-on | Runner label(s) or self-hosted spec |
| steps | Ordered list of steps to run |
| uses | Call a reusable workflow instead of defining steps |
| timeout-minutes | Cancel the job if it exceeds N minutes (default 360) |
Examples
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4 Minimal single-job workflow with a job timeout
jobs:
test:
runs-on: ubuntu-latest
steps: [...]
deploy:
needs: test
runs-on: ubuntu-latest
steps: [...] deploy runs only after test succeeds
jobs:
call:
uses: ./.github/workflows/reusable.yml
secrets: inherit Job that delegates to a reusable workflow
Gotcha
Job IDs must be valid identifiers — leading digits are not allowed; the `needs` graph is evaluated as a DAG and cycles fail the workflow at parse time.
Related keywords
runs-on:
Selects the runner (or runner group) that will execute the job. Accepts a single label, an array to match multiple labels (self-hosted), or an object form for larger runners and runner groups.
needs:
Declares job dependencies so the current job waits for the listed jobs to complete successfully. Also exposes their outputs via `needs.<job_id>.outputs.<name>` and their result via `needs.<job_id>.result`.
if:
Conditional expression that controls whether a job or step runs. On a job it gates the entire job; on a step it gates only that step, and both automatically wrap the value in an implicit `${{ }}` if omitted.
outputs:
Declares values a job exposes to downstream jobs that `needs:` it. Values are usually pulled from step outputs written to `$GITHUB_OUTPUT`.