GitHub Actions desde cero: tu primer pipeline CI/CD en 15 minutos
Cómo funcionan los workflows, jobs y steps de GitHub Actions, con un ejemplo completo para Node.js con tests, build y deploy.
Qué es GitHub Actions y por qué usarlo
GitHub Actions es la plataforma de CI/CD integrada en GitHub. No requiere servidores propios, se factura por minuto de ejecución (con una cuota gratuita generosa en repos públicos y bastante en privados) y se configura con archivos YAML dentro de .github/workflows/. Frente a Jenkins, GitLab CI o CircleCI, su ventaja es que los eventos (push, pull_request, release, schedule) se disparan sin webhooks manuales y el marketplace tiene miles de acciones reutilizables.
Anatomía de un workflow
Un archivo bajo .github/workflows/ci.yml contiene:
- name — cómo aparece en la pestaña Actions.
- on — qué evento dispara el workflow (
push,pull_request,workflow_dispatchmanual,schedulecron). - jobs — uno o varios trabajos. Por defecto se ejecutan en paralelo; usa
needs:para encadenar. - runs-on — el runner (
ubuntu-latest,macos-latest,windows-latesto self-hosted). - steps — acciones o comandos shell secuenciales dentro del job.
Un pipeline mínimo para Node.js:
name: CI
on:
push:
branches: [main]
pull_request:
jobs:
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
Si no quieres pelearte con la indentación YAML, el generador de GitHub Actions produce este esqueleto en segundos.
Secretos y variables
Nunca pongas API keys en el YAML. Guárdalos en Settings → Secrets and variables → Actions y referéncialos como ${{ secrets.MI_TOKEN }}. Los secretos están cifrados en reposo y solo se descifran en el runner durante la ejecución. Las variables (no cifradas) valen para configuración pública como versiones o URLs.
Cache: la diferencia entre 30s y 4 min
Instalar dependencias es lo más lento del pipeline. Usa cache en la acción de setup o actions/cache@v4 manual con una key basada en el lockfile:
- uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
Matriz de builds
Para probar contra varias versiones de Node o Python usa una matrix:
strategy:
matrix:
node: [18, 20, 22]
steps:
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
GitHub lanzará tres jobs en paralelo, uno por versión.
Deploy condicional a main
El paso de deploy solo debe ejecutarse cuando el push va a la rama principal, no en cada PR:
- name: Deploy
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
run: ./scripts/deploy.sh
Buenas prácticas rápidas
- Pinning por SHA: en workflows sensibles, usa
uses: actions/checkout@a12345...en vez de@v4. Bloquea supply-chain attacks si alguien compromete una tag mutable. - Timeouts: añade
timeout-minutes: 15a cada job para evitar workflows colgados que agotan tu cuota. - Concurrency: usa
concurrency: { group: ${{ github.ref }}, cancel-in-progress: true }para cancelar builds antiguas de la misma PR. - Artifacts para propagar resultados entre jobs; outputs para pasar variables.
Con estos ingredientes tienes CI/CD serio en el mismo repo donde vive el código, sin infraestructura adicional.
Herramientas relacionadas
Genera un workflow CI listo para Node, Python o Go con test, build y deploy opcional.
Combina plantillas oficiales (Node, Python, Go, IDE, OS…) en un .gitignore listo.
Genera Dockerfiles optimizados para Node.js, Python, Go, Java o sitios estáticos, con multi-stage y usuario no-root.