Testar seu código em apenas uma versão de Node.js, Python ou Ruby é arriscado. E se seu código quebrar no Python 3.9 mas funcionar no 3.12? E se houver bugs específicos do Windows que você não detecta no Linux? Matrix Strategy do GitHub Actions resolve isso de forma elegante.
O Problema: Compatibilidade Multi-Versão
Imagine este cenário comum:
# Workflow simples
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm testProblemas:
- ❌ Só testa em Node.js 20
- ❌ Só testa em Ubuntu
- ❌ Usuários com Node 16 ou 18 podem ter problemas
- ❌ Bugs específicos do Windows ou macOS passam despercebidos
Para testar em 3 versões do Node × 3 SOs = 9 combinações, você precisaria de 9 jobs separados. Muito código duplicado!
A Solução: Matrix Strategy
Matrix Strategy permite definir múltiplas dimensões de teste em um único job:
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [16, 18, 20]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm testResultado: 9 jobs executados em paralelo automaticamente! 🚀
Como Funciona a Matrix
Sintaxe Básica
strategy:
matrix:
# Cada chave define uma dimensão
language: [node, python, go]
version: [latest, stable]GitHub Actions cria produto cartesiano de todas as combinações:
- language: node, version: latest
- language: node, version: stable
- language: python, version: latest
- language: python, version: stable
- language: go, version: latest
- language: go, version: stable
Total: 3 × 2 = 6 jobs
Acessando Valores da Matrix
Use ${{ matrix.variavel }} para acessar o valor atual:
steps:
- name: Print current combination
run: |
echo "Testing ${{ matrix.language }} version ${{ matrix.version }}"Exemplos Práticos
1. Teste Multi-Versão Node.js
name: Node.js CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16.x, 18.x, 20.x, 21.x]
steps:
- uses: actions/checkout@v4
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
- name: Run lint
run: npm run lintResultado: Testa em Node 16, 18, 20 e 21 simultaneamente.
2. Teste Cross-Platform
name: Cross-Platform Tests
on: [push, pull_request]
jobs:
test:
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
python-version: ['3.9', '3.10', '3.11', '3.12']
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Setup Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Run tests
run: pytestResultado: 3 SOs × 4 versões Python = 12 jobs em paralelo
3. Matrix com Múltiplas Dimensões
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
node-version: [18, 20]
database: [postgres, mysql, sqlite]
include:
# Adiciona combinação específica
- os: macos-latest
node-version: 20
database: postgres
steps:
- name: Start database
run: |
echo "Starting ${{ matrix.database }} on ${{ matrix.os }}"Resultado: (2 × 2 × 3) + 1 = 13 jobs
Recursos Avançados
1. Include - Adicionar Combinações Específicas
strategy:
matrix:
os: [ubuntu-latest]
node-version: [18, 20]
include:
# Testa Node 16 apenas no Ubuntu
- os: ubuntu-latest
node-version: 16
# Testa Node 20 no macOS também
- os: macos-latest
node-version: 20
# Adiciona variáveis extras para combinação específica
- os: ubuntu-latest
node-version: 20
experimental: true2. Exclude - Remover Combinações Indesejadas
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [16, 18, 20]
exclude:
# Node 16 não suportado no Windows
- os: windows-latest
node-version: 16
# Economizar runners - pular macOS para Node 18
- os: macos-latest
node-version: 18Resultado: (3 × 3) - 2 = 7 jobs ao invés de 9
3. Fail-Fast (Padrão: true)
strategy:
fail-fast: false # Continua outros jobs mesmo se um falhar
matrix:
version: [1, 2, 3, 4, 5]fail-fast: true (padrão): Cancela todos os jobs se um falhar
fail-fast: false: Roda todos independentemente
4. Max-Parallel - Limitar Execuções Simultâneas
strategy:
max-parallel: 3 # Apenas 3 jobs por vez
matrix:
version: [1, 2, 3, 4, 5, 6, 7, 8]Útil para:
- Economizar minutos de CI
- Evitar rate limiting de APIs externas
- Limitar uso de recursos
Casos de Uso Reais
1. Biblioteca NPM Multi-Versão
name: NPM Package CI
on: [push, pull_request]
jobs:
test:
strategy:
matrix:
node-version: [16, 18, 20, 22]
os: [ubuntu-latest, windows-latest, macos-latest]
exclude:
# Node 22 ainda experimental
- os: windows-latest
node-version: 22
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm test
- run: npm run build
- name: Test installation
run: |
npm pack
npm install -g *.tgz2. Aplicação com Múltiplos Bancos
strategy:
matrix:
database:
- type: postgres
version: '14'
port: 5432
- type: postgres
version: '15'
port: 5432
- type: mysql
version: '8.0'
port: 3306
- type: mariadb
version: '10.11'
port: 3306
steps:
- name: Start ${{ matrix.database.type }}
run: |
docker run -d \
-p ${{ matrix.database.port }}:${{ matrix.database.port }} \
${{ matrix.database.type }}:${{ matrix.database.version }}
- name: Run migrations
env:
DATABASE_URL: ${{ matrix.database.type }}://localhost:${{ matrix.database.port }}/test
run: npm run migrate
- name: Run tests
run: npm test3. Build Multi-Arquitetura
strategy:
matrix:
include:
- arch: amd64
os: ubuntu-latest
- arch: arm64
os: ubuntu-latest
- arch: armv7
os: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Build for ${{ matrix.arch }}
run: |
docker buildx build \
--platform linux/${{ matrix.arch }} \
-t myapp:${{ matrix.arch }} \
.Naming e Identificação
Nome Dinâmico do Job
jobs:
test:
name: Test on ${{ matrix.os }} with Node ${{ matrix.node-version }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
node-version: [18, 20]
runs-on: ${{ matrix.os }}Resultado na UI:
- Test on ubuntu-latest with Node 18
- Test on ubuntu-latest with Node 20
- Test on windows-latest with Node 18
- Test on windows-latest with Node 20
Matrix com Outputs
Você pode usar outputs de uma matrix em jobs subsequentes:
jobs:
build:
strategy:
matrix:
version: [v1, v2, v3]
outputs:
# Não funciona diretamente - precisa workaround
artifact-name: myapp-${{ matrix.version }}
steps:
- run: echo "Building ${{ matrix.version }}"
# Alternativa: usar artefatos nomeados
deploy:
needs: build
steps:
- uses: actions/download-artifact@v4
with:
pattern: myapp-*Performance e Custos
Minutos de Consumo
Exemplo: Matrix com 12 combinações, cada uma rodando 5 minutos.
fail-fast: true (se nenhum falhar): 5 minutos × 12 = 60 minutos de runner
fail-fast: true (se um falhar em 2min): ~2-5 minutos (cancela os outros)
fail-fast: false: Sempre 60 minutos
Otimizações
- Use cache agressivamente:
- uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ matrix.node-version }}-${{ hashFiles('**/package-lock.json') }}- Priorize combinações importantes:
include:
- os: ubuntu-latest
node-version: 20
priority: high # Rode isso primeiro- Use max-parallel para controlar custo:
strategy:
max-parallel: 2 # Máximo 2 jobs por vez em contas freeDebugging Matrix
Ver Todas as Combinações
jobs:
debug:
strategy:
matrix:
os: [ubuntu, windows, macos]
version: [1, 2, 3]
steps:
- name: Print matrix
run: |
echo "OS: ${{ matrix.os }}"
echo "Version: ${{ matrix.version }}"
echo "Runner: ${{ runner.os }}"Testar Uma Combinação
Use workflow_dispatch com inputs:
on:
workflow_dispatch:
inputs:
os:
type: choice
options: [ubuntu-latest, windows-latest, macos-latest]
node-version:
type: choice
options: [16, 18, 20]
jobs:
test:
runs-on: ${{ inputs.os }}
steps:
- uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}Best Practices
- ✅ Sempre teste versões LTS + latest
- ✅ Use fail-fast: false em PRs para ver todos os problemas
- ✅ Documente quais combinações são obrigatórias
- ✅ Use exclude para economizar em combinações não importantes
- ✅ Nomeie jobs descritivamente
- ❌ Evite matrices muito grandes (>20 combinações)
- ❌ Não duplique lógica - use matrix
Conclusão
Matrix Strategy transforma:
# De 100+ linhas de código duplicado
test-node-16-ubuntu: ...
test-node-18-ubuntu: ...
test-node-20-ubuntu: ...
test-node-16-windows: ...
# ... etcPara:
# 20 linhas elegantes
strategy:
matrix:
os: [ubuntu, windows, macos]
node: [16, 18, 20]Benefícios:
- ⏱️ Economia de tempo - testes em paralelo
- 🎯 Mais cobertura - múltiplas combinações facilmente
- 🔧 Manutenção simples - um lugar para atualizar
- 💰 Controle de custos - max-parallel e exclude
Já usa Matrix Strategy? Compartilhe nos comentários quantas combinações você testa!
#GitHubActions #CI #Testing #DevOps

Comments