GitHub Actions#
GitHub Actions’ matrix feature pairs naturally with cargo fc matrix to test feature combinations in parallel.
Approach 1 — fan out one job per combination#
First, a reusable workflow that computes the feature matrix:
# .github/workflows/feature-matrix.yaml
name: feature-matrix
on:
workflow_call:
outputs:
matrix:
description: "feature matrix"
value: ${{ jobs.matrix.outputs.matrix }}
jobs:
matrix:
name: Generate feature matrix
runs-on: ubuntu-24.04
outputs:
matrix: ${{ steps.compute-matrix.outputs.matrix }}
steps:
- uses: actions/checkout@v4
- uses: romnn/cargo-feature-combinations@main
- name: Compute feature matrix
id: compute-matrix
run: |-
MATRIX="$(cargo fc matrix)"
echo "${MATRIX}"
echo "matrix=${MATRIX}" >> "$GITHUB_OUTPUT"Then consume it to build every combination in parallel:
# .github/workflows/build.yaml
name: build
on:
push: {}
pull_request: {}
jobs:
feature-matrix:
uses: ./.github/workflows/feature-matrix.yaml
build:
name: build ${{ matrix.package.name }} (${{ matrix.os }}, features ${{ matrix.package.features }})
runs-on: ${{ matrix.os }}
needs: [feature-matrix]
strategy:
fail-fast: false
matrix:
os: [macos-latest, ubuntu-24.04]
package: ${{ fromJson(needs.feature-matrix.outputs.matrix) }}
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- name: Build
run: >-
cargo build
--package "${{ matrix.package.name }}"
--features "${{ matrix.package.features }}"
--all-targetsThe same pattern works for test.yaml or lint.yaml. Up to 256 feature sets can be processed per job.
Custom metadata#
If you configure matrix metadata, it’s available as matrix.package.metadata:
name: build ${{ matrix.package.name }} (${{ matrix.package.metadata.kind }})Fanning out over targets too#
If you declare configured targets, every matrix row carries a target field:
strategy:
fail-fast: false
matrix:
package: ${{ fromJson(needs.feature-matrix.outputs.matrix) }}
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.package.target }}
- run: >-
cargo check
--package "${{ matrix.package.name }}"
--features "${{ matrix.package.features }}"
--target "${{ matrix.package.target }}"Approach 2 — one job, the whole matrix#
For linting or checking, where you don’t need a separate CI job per combination, a single invocation iterates every configured target and feature combination:
- uses: actions/checkout@v4
- uses: romnn/cargo-feature-combinations@main
- run: cargo fc clippy # or: cargo fc checkIf the runner doesn’t already have the configured targets installed, either preinstall them (recommended — more reproducible and cache-friendly) or add --install-missing-targets:
- uses: dtolnay/rust-toolchain@stable
with:
targets: x86_64-unknown-linux-gnu, wasm32-unknown-unknownAdd --aggregate-targets to batch each combination’s targets into one Cargo invocation for extra throughput on many-core runners.
The setup action#
romnn/cargo-feature-combinations@main downloads a released binary and puts cargo fc on the PATH. It accepts an optional version input (defaults to the latest release).