Example: Matrix Build
Test across multiple operating systems and Node.js versions.
Workflow
ts
import { getAction, Job, Workflow } from "../../generated/index.js";
const checkout = getAction("actions/checkout@v5");
const setupNode = getAction("actions/setup-node@v4");
// Define matrix test job
const test = new Job("${{ matrix.os }}", {
strategy: {
matrix: {
os: ["ubuntu-latest", "macos-latest", "windows-latest"],
node: ["18", "20", "22"],
},
},
})
.steps(s => s
.add(checkout({
name: "Checkout code",
}))
.add(setupNode({
name: "Setup Node.js ${{ matrix.node }}",
with: {
"node-version": "${{ matrix.node }}",
cache: "npm",
},
}))
.add({
name: "Install dependencies",
run: "npm ci",
})
.add({
name: "Run tests",
run: "npm test",
})
);
// Create workflow
const workflow = new Workflow({
name: "Matrix Test",
on: {
push: {
branches: ["main"],
},
pull_request: {
branches: ["main"],
},
},
}).jobs(j => j
.add("test", test)
);
workflow.build("matrix-test");Generated YAML
yaml
name: Matrix Test
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os:
- ubuntu-latest
- macos-latest
- windows-latest
node:
- '18'
- '20'
- '22'
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Setup Node.js ${{ matrix.node }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
cache: npm
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm testThis creates 9 jobs (3 OS × 3 Node versions).
Matrix Variations
Include/Exclude
typescript
{
strategy: {
matrix: {
os: ["ubuntu-latest", "macos-latest", "windows-latest"],
node: ["18", "20", "22"],
include: [
{
os: "ubuntu-latest",
node: "16",
experimental: true,
},
],
exclude: [
{
os: "macos-latest",
node: "18", // Skip Node 18 on macOS
},
],
},
},
}Fail-Fast
typescript
{
strategy: {
"fail-fast": false, // Continue even if one job fails
matrix: {
node: ["18", "20", "22"],
},
},
}Max Parallel
typescript
{
strategy: {
"max-parallel": 2, // Run max 2 jobs in parallel
matrix: {
node: ["18", "20", "22"],
},
},
}Advanced Example: Test + Build
ts
import { getAction, Job, Workflow } from "../../generated/index.js";
const checkout = getAction("actions/checkout@v5");
const setupNode = getAction("actions/setup-node@v4");
const uploadArtifact = getAction("actions/upload-artifact@v4");
// Matrix test job
const test = new Job("${{ matrix.os }}", {
strategy: {
matrix: {
os: ["ubuntu-latest", "macos-latest", "windows-latest"],
node: ["20"],
},
},
})
.steps(s => s
.add(checkout({}))
.add(setupNode({
with: { "node-version": "${{ matrix.node }}" },
}))
.add({ run: "npm ci" })
.add({ run: "npm test" })
);
// Build job (runs after all tests pass)
const build = new Job("ubuntu-latest", {
needs: ["test"],
})
.steps(s => s
.add(checkout({}))
.add(setupNode({ with: { "node-version": "20" } }))
.add({ run: "npm ci" })
.add({ run: "npm run build" })
.add(uploadArtifact({
with: {
name: "build-output",
path: "dist/",
},
}))
);
// Create workflow
const workflow = new Workflow({
name: "Test and Build",
on: {
push: { branches: ["main"] },
},
}).jobs(j => j
.add("test", test)
.add("build", build)
);
workflow.build("test-build");Real-World Example: Cross-Platform Binary
typescript
const build = new Job("${{ matrix.os }}", {
strategy: {
matrix: {
include: [
{ os: "ubuntu-latest", target: "x86_64-unknown-linux-gnu", name: "linux-x64" },
{ os: "macos-latest", target: "x86_64-apple-darwin", name: "darwin-x64" },
{ os: "macos-latest", target: "aarch64-apple-darwin", name: "darwin-arm64" },
{ os: "windows-latest", target: "x86_64-pc-windows-msvc", name: "win32-x64" },
],
},
},
})
.steps(s => s
.add(checkout({}))
.add({
name: "Build binary",
run: "cargo build --release --target ${{ matrix.target }}",
})
.add(uploadArtifact({
with: {
name: "binary-${{ matrix.name }}",
path: "target/${{ matrix.target }}/release/",
},
}))
);Next Steps
- See Composite Action
- Learn about Job Dependencies
