---
title: Run GitHub Actions Steps in Parallel With background
description: GitHub Actions steps can now run in parallel with background: true, wait, wait-all, cancel, and parallel. Here is when to use each keyword.
date: 2026-08-13T00:00:00.000Z
category: dev-tools
tags: github-actions, ci-cd, workflow-syntax, yaml
---

## Quick Answer

Use `background: true` plus `wait`, `wait-all`, or `cancel` when you need fine control, starting a service early and doing other work before waiting on it. Use the `parallel` keyword when you just want a group of independent steps to run together and have the job wait for all of them automatically. Both shipped 2026-06-25 and only apply within a single job.

## 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. `wait` can target one or more specific background steps, while `wait-all` pauses 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:

```yaml title=".github/workflows/test.yml"
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-db
```

`npm 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 `id`s and `wait` steps:

```yaml title=".github/workflows/build.yml"
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 package
```

<Callout
  type="info"
  title="Exact 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](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions)
  before shipping it to a production pipeline.
</Callout>

## 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](https://github.blog/changelog/2026-06-25-actions-steps-can-now-be-run-in-parallel/), published 2026-06-25. Browse more posts like this in the [Dev Tools](/dev-tools) archive.
