GitHub Actions CI/CD: Crea, prueba e implementa flujos de trabajo desde cero
Aprende a configurar GitHub Actions para integración y despliegue continuos. Cubre triggers, jobs, matrices, secrets, caché, Docker y ejemplos de flujos de trabajo del mundo real.
GitHub Actions convierte cada push, pull request y merge en un pipeline automatizado: ejecuta pruebas, genera artefactos, analiza vulnerabilidades y despliega a producción. Es la plataforma CI/CD que vive directamente dentro de tu repositorio, sin infraestructura que gestionar.
Cómo funciona GitHub Actions
Cada workflow es un archivo YAML en .github/workflows/. Cuando se dispara un evento trigger, GitHub lanza una máquina virtual nueva, ejecuta tus jobs y reporta los resultados, todo en cuestión de segundos.
Push a main
↓
Workflow disparado
↓
Job: Build & Test (ubuntu-latest)
├── Paso 1: Checkout del código
├── Paso 2: Instalar Node.js
├── Paso 3: npm ci
├── Paso 4: npm test
└── Paso 5: npm run build
↓
✅ Todas las verificaciones pasaron
Tu primer workflow
Crea .github/workflows/ci.yml:
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build:
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
- run: npm run build
Eso es todo. Cada push a main y cada PR ahora ejecuta tu suite de pruebas automáticamente.
Triggers: cuándo se ejecutan los workflows
Eventos de código
on:
push:
branches: [main, develop]
paths: ['src/**', 'package.json'] # Solo ejecutar cuando estos cambian
pull_request:
types: [opened, synchronize]
Programado (cron)
on:
schedule:
- cron: '0 6 * * 1' # Cada lunes a las 6:00 UTC
Ejecución manual
on:
workflow_dispatch:
inputs:
environment:
description: 'Destino de despliegue'
required: true
type: choice
options: [staging, production]
Esto añade un botón "Run workflow" en la interfaz de GitHub donde puedes seleccionar parámetros.
Workflows reutilizables
on:
workflow_call:
inputs:
node-version:
type: string
default: '20'
Llámalo desde otro workflow con uses: ./.github/workflows/reusable.yml.
Jobs y steps
Jobs en paralelo
Los jobs se ejecutan en paralelo por defecto:
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm run lint
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm test
build:
runs-on: ubuntu-latest
needs: [lint, test] # Espera a que ambos pasen
steps:
- uses: actions/checkout@v4
- run: npm run build
Estrategia de matriz: prueba en múltiples versiones
Ejecuta el mismo job en múltiples configuraciones:
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18, 20, 22]
os: [ubuntu-latest, windows-latest]
fail-fast: false
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm test
Esto crea 6 jobs en paralelo (3 versiones × 2 sistemas operativos).
Secrets y variables de entorno
Usar secrets
Almacena valores sensibles en Settings → Secrets and variables → Actions:
steps:
- name: Deploy
env:
API_KEY: ${{ secrets.API_KEY }}
DATABASE_URL: ${{ secrets.DATABASE_URL }}
run: ./deploy.sh
Los secrets se enmascaran en los logs y nunca se exponen a los forks.
Variables de entorno
# A nivel de workflow
env:
NODE_ENV: production
jobs:
build:
# A nivel de job
env:
CI: true
steps:
- name: Build
# A nivel de step
env:
VITE_API_URL: https://api.example.com
run: npm run build
Caché para compilaciones más rápidas
Sin caché, cada ejecución descarga todas las dependencias desde cero. El caché reduce los tiempos de compilación entre un 50 y un 80 %:
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm # Caché de npm integrado
# O caché manual para otras herramientas
- uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
Artefactos: compartir datos entre jobs
Sube las salidas de compilación desde un job y descárgalas en otro:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm run build
- uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v4
with:
name: dist
- run: ./deploy.sh
Ejemplos de flujos de trabajo del mundo real
Build y push de Docker
name: Docker
on:
push:
tags: ['v*']
permissions:
packages: write
jobs:
docker:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@v5
with:
push: true
tags: ghcr.io/${{ github.repository }}:${{ github.ref_name }}
cache-from: type=gha
cache-to: type=gha,mode=max
Despliegue a Cloudflare Pages
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- run: npm ci && npm run build
- uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
command: pages deploy dist --project-name=my-site
Release con changelog
name: Release
on:
push:
tags: ['v*.*.*']
permissions:
contents: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Generar changelog
run: |
git log $(git describe --tags --abbrev=0 HEAD^)..HEAD \
--pretty=format:"- %s" > CHANGELOG.md
- uses: softprops/action-gh-release@v2
with:
body_path: CHANGELOG.md
generate_release_notes: true
Ejecución condicional
Controla cuándo se ejecutan los steps y los jobs:
steps:
- name: Desplegar a producción
if: github.ref == 'refs/heads/main'
run: ./deploy-prod.sh
- name: Desplegar a staging
if: github.event_name == 'pull_request'
run: ./deploy-staging.sh
- name: Notificar en caso de fallo
if: failure()
run: curl -X POST ${{ secrets.SLACK_WEBHOOK }} -d '{"text":"¡La compilación falló!"}'
Buenas prácticas de seguridad
1. Fija las versiones de las actions al SHA
# ❌ Tag mutable — podría verse comprometido
- uses: actions/checkout@v4
# ✅ Fijado al SHA exacto del commit
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
2. Usa permisos de mínimo privilegio
permissions:
contents: read # Solo lo necesario
packages: write
3. Nunca imprimas secrets en pantalla
# ❌ NUNCA hagas esto
- run: echo ${{ secrets.API_KEY }}
# ✅ Usa variables de entorno
- env:
API_KEY: ${{ secrets.API_KEY }}
run: ./script-that-uses-api-key.sh
4. Limita los permisos para PRs de forks
on:
pull_request_target: # Se ejecuta en el contexto de la rama base
types: [opened, synchronize]
Depurar workflows fallidos
- Revisa los logs — Haz clic en cualquier step fallido para ver la salida completa
- Añade logging de depuración — Establece el secret
ACTIONS_STEP_DEBUGentrue - Usa
actlocalmente — Ejecuta workflows en tu máquina con nektos/act - Accede por SSH al runner — Usa
mxschmitt/action-tmatepara depuración interactiva
Crea workflows visualmente
¿No quieres escribir YAML a mano? Usa nuestro GitHub Actions Generator para construir workflows visualmente con plantillas para Node.js, Python, Docker, despliegues y más — y descarga YAML listo para producción.
Conclusión
GitHub Actions te ofrece CI/CD que vive dentro de tu repositorio:
- Empieza simple — Un archivo de workflow con build + test
- Añade caché — Reduce los tiempos de compilación con
actions/cacheo el caché de lenguaje integrado - Usa la matriz — Prueba en múltiples versiones y sistemas operativos
- Protege los secrets — Nunca los escribas en el código; usa siempre secrets cifrados
- Automatiza todo — Releases, despliegues, análisis de seguridad, tareas programadas
El mejor pipeline CI/CD es el que se ejecuta en cada commit sin que tengas que pensar en ello. Configúralo una vez y deja que GitHub se encargue del resto.