Automatizar flujos de trabajo con GitHub Actions
Patrones prácticos de GitHub Actions para automatizar CI/CD, calidad de código, actualizaciones de dependencias y releases, con workflows reutilizables.

GitHub Actions empezó como una herramienta de CI sencilla, pero se ha convertido en una plataforma completa de automatización de flujos de trabajo. Más allá de ejecutar tests, los equipos la usan para imponer calidad de código, automatizar releases, mantener las dependencias actualizadas y coordinar despliegues multiservicio. La clave está en entender los patrones que hacen que los workflows sigan siendo mantenibles a medida que crecen.
La mayoría de los equipos empieza con un único archivo de workflow que lo hace todo. Eso funciona hasta que deja de funcionar. Esta guía cubre los patrones que escalan.
Pipeline básico de CI
Todo repositorio necesita un pipeline de CI que se ejecute en las pull requests. Empieza simple y añade complejidad solo cuando sea necesaria.
# .github/workflows/ci.yml
name: CI
on:
pull_request:
branches: [main]
push:
branches: [main]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- run: npm ci
- run: npm run lint
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- run: npm ci
- run: npm test -- --coverage
- uses: actions/upload-artifact@v4
with:
name: coverage-report
path: coverage/Lint y test se ejecutan en paralelo: si el linting falla, lo ves de inmediato sin esperar a los tests. Ambos jobs cachean node_modules a través de la caché integrada de la acción setup-node.
Builds con matrix para pruebas en varios entornos
Prueba con múltiples versiones de Node, sistemas operativos o versiones de bases de datos usando estrategias de matrix.
# ❌ Separate jobs for each environment — repetitive and hard to maintain
jobs:
test-node-18:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 18
- run: npm ci && npm test
test-node-20:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci && npm test# ✅ Matrix strategy — one job definition, multiple environments
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
node-version: [18, 20, 22]
os: [ubuntu-latest, windows-latest]
fail-fast: false # Don't cancel other jobs if one fails
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- run: npm ci
- run: npm testfail-fast: false es importante: sin él, un fallo en una combinación cancela todos los jobs en ejecución. Conviene ver todos los fallos a la vez, no arreglarlos uno por uno.
Workflows reutilizables
Cuando varios repositorios necesitan el mismo pipeline de CI, el YAML duplicado se extiende por los repos y acaba divergiendo. Los workflows reutilizables resuelven esto.
# .github/workflows/reusable-node-ci.yml (in a shared repository)
name: Reusable Node CI
on:
workflow_call:
inputs:
node-version:
required: false
type: string
default: '20'
run-e2e:
required: false
type: boolean
default: false
secrets:
NPM_TOKEN:
required: false
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
cache: 'npm'
registry-url: 'https://registry.npmjs.org'
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- run: npm ci
- run: npm run build
- run: npm test
e2e:
if: ${{ inputs.run-e2e }}
runs-on: ubuntu-latest
needs: build-and-test
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
cache: 'npm'
- run: npm ci
- run: npx playwright install --with-deps
- run: npm run test:e2e# .github/workflows/ci.yml (in consuming repositories)
name: CI
on:
pull_request:
branches: [main]
jobs:
ci:
uses: my-org/shared-workflows/.github/workflows/reusable-node-ci.yml@main
with:
node-version: '20'
run-e2e: true
secrets:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}Los cambios en el workflow compartido se propagan a todos los repositorios que lo referencian. Fíjalo a un SHA o tag específico para mayor estabilidad en repos de producción.
Workflow de release automatizado
Automatiza el bump de versión y la generación del changelog basándote en conventional commits.
# .github/workflows/release.yml
name: Release
on:
push:
branches: [main]
permissions:
contents: write
pull-requests: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Need full history for changelog
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
registry-url: 'https://registry.npmjs.org'
- run: npm ci
- run: npm run build
- run: npm test
- name: Determine version bump
id: version
run: |
# Check commit messages since last tag
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
COMMITS=$(git log ${LAST_TAG}..HEAD --pretty=format:"%s")
if echo "$COMMITS" | grep -q "^feat!:\|^BREAKING CHANGE:"; then
echo "bump=major" >> "$GITHUB_OUTPUT"
elif echo "$COMMITS" | grep -q "^feat:"; then
echo "bump=minor" >> "$GITHUB_OUTPUT"
else
echo "bump=patch" >> "$GITHUB_OUTPUT"
fi
- name: Bump version and create tag
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
npm version ${{ steps.version.outputs.bump }} -m "chore: release v%s"
git push --follow-tags
- name: Publish to npm
run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}Workflows condicionales con filtros de rutas
Los monorepos grandes no deberían ejecutar todas las verificaciones ante cualquier cambio. Los filtros de rutas garantizan que solo se disparen los workflows relevantes.
# ❌ Every PR runs the full pipeline regardless of what changed
on:
pull_request:
branches: [main]# ✅ Only run when relevant files change
on:
pull_request:
branches: [main]
paths:
- 'src/**'
- 'package.json'
- 'package-lock.json'
- '.github/workflows/ci.yml'
# Also useful: ignore paths
on:
pull_request:
branches: [main]
paths-ignore:
- 'docs/**'
- '*.md'
- '.vscode/**'Para servicios de un monorepo, usa archivos de workflow separados con filtros de rutas por servicio. Un cambio en services/auth/** solo dispara el pipeline del servicio auth.
Caché y rendimiento
La velocidad del CI afecta directamente a la productividad del desarrollador. Cachea de forma agresiva y paraleliza todo lo posible.
jobs:
install:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- run: npm ci
# Cache the entire node_modules for downstream jobs
- uses: actions/cache/save@v4
with:
path: node_modules
key: modules-${{ hashFiles('package-lock.json') }}
lint:
needs: install
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/cache/restore@v4
with:
path: node_modules
key: modules-${{ hashFiles('package-lock.json') }}
- run: npm run lint
test-unit:
needs: install
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/cache/restore@v4
with:
path: node_modules
key: modules-${{ hashFiles('package-lock.json') }}
- run: npm run test:unit
test-integration:
needs: install
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/cache/restore@v4
with:
path: node_modules
key: modules-${{ hashFiles('package-lock.json') }}
- run: npm run test:integrationInstala una vez y luego ramifica hacia lint, tests unitarios y tests de integración en paralelo. La división cache/save y cache/restore evita descargar las dependencias tres veces.
Conclusiones clave
- Separa las responsabilidades en jobs paralelos: lint, test y build deberían ejecutarse de forma concurrente, no secuencial
- Usa builds con matrix para pruebas en varios entornos y configura
fail-fast: falsepara ver todos los fallos - Extrae workflows reutilizables cuando varios repos comparten la misma lógica de pipeline
- Usa filtros de rutas para evitar ejecutar workflows irrelevantes en monorepos
- Cachea de forma agresiva: instala las dependencias una vez y compártelas vía caché entre jobs paralelos
- Automatiza los releases con conventional commits y workflows de bump de versión


