What used to force artificial serialization
Every step in a GitHub Actions job has always run strictly in order, one finishing before the next starts. That’s fine when steps genuinely depend on each other, but it forces unnecessary waiting when they don’t: three independent build tasks that don’t share state, or a background service (a test database, a mock API) that a later step needs running but doesn’t need to wait on immediately.
GitHub’s changelog, published 2026-06-25, adds four new step-level keywords to fix that:
“
background: true… runs a step asynchronously and immediately continues to the next step.”
“
wait/wait-all… pauses execution until one or more named background steps complete.waitcan target one or more specific background steps, whilewait-allpauses until all prior background steps have completed.”
“
cancel… gracefully terminates a background step when you no longer need it, enabling you to start long-running services with a background step.”
“
parallel… takes a group of steps and converts them to background steps with a wait after, enabling you to easily run multiple steps in parallel.”
None of these change how a job is triggered or how jobs relate to each other. They’re new keys inside an existing steps: block, not a new job or workflow structure.
Structural Comparison Matrix
| Operational Aspect | Plain sequential steps (default) | background + wait/wait-all/cancel | parallel |
|---|---|---|---|
| Execution order | Strictly one after another | A step starts, the job moves on immediately | A whole step group starts together |
| Control over waiting | N/A, waiting is implicit and total | Explicit: choose exactly which background step(s) to wait for, or none at all | Implicit: the group is waited on automatically after it |
| Best fit | Steps with a real order dependency | A background service another step needs, started early and stopped or waited on later | Several independent steps with no order dependency between them |
| Syntax overhead | None | An id on the background step, plus a separate wait/cancel step | Lowest, one parallel: block |
Add background steps to a job
A common case: a test suite needs a real database running, but starting it doesn’t need to block installing dependencies. Give the background step an id, mark it background: true, and reference that id later:
jobs:
integration-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: Start test database
id: test-db
background: true
run: docker run -d --name test-db -p 5432:5432 postgres:16
- name: Install dependencies
run: npm ci
- name: Wait for test database
wait: test-db
- name: Run integration tests
run: npm run test:integration
- name: Stop test database
cancel: test-dbnpm ci starts running the moment docker run is dispatched, not after it finishes, since the database step already handed control back. The wait: test-db step is where the job actually pauses until the container is up, right before the tests that need it.
Group independent steps with parallel
For steps that have no order dependency on each other at all, wrapping them in parallel avoids hand-managing ids and wait steps:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- parallel:
- name: Build frontend bundle
run: npm run build:frontend
- name: Build backend bundle
run: npm run build:backend
- name: Build docs site
run: npm run build:docs
- name: Package release
run: npm run packageExact syntax, verified against the changelog's own description
GitHub’s changelog describes the mechanics of background, wait,
wait-all, cancel, and parallel in the exact terms quoted above, but
doesn’t publish a full example workflow in the entry itself. The YAML shapes
here match that described behavior, id-based background steps referenced by a
later wait or cancel, and parallel grouping a set of steps with an
implicit wait after, but weren’t run against a live workflow here. Confirm the
exact indentation against GitHub’s workflow syntax
reference
before shipping it to a production pipeline.
Would this help this site’s own CI?
This site’s .github/workflows/ci.yml runs its build job’s steps in strict sequence: install, lint, format check, Astro check, unit tests, build, then Playwright install and end-to-end tests. Lint, the format check, and the Astro check don’t depend on each other, only on npm ci finishing first, which makes them a real candidate for a parallel block once this repo adopts a runner fleet new enough to support it. The unit tests and the build step still need to stay sequential, since the end-to-end tests run against the built output.
Confirmed version
Sourced from GitHub’s changelog entry announcing the new step keywords, published 2026-06-25. Browse more posts like this in the Dev Tools archive.







