Todo equipo de desarrollo moderno necesita una forma confiable de probar, construir y desplegar código automáticamente. GitHub Actions proporciona una plataforma CI/CD potente integrada directamente en GitHub, eliminando la necesidad de servicios externos como Jenkins o CircleCI. En esta guía, aprenderás cómo crear flujos de trabajo desde cero, ejecutar pruebas automatizadas, construir artefactos y desplegar aplicaciones — todo activado por un simple git push.
¿Qué Es CI/CD?
Integración Continua (CI) es la práctica de probar y validar automáticamente el código cada vez que un desarrollador hace push de cambios. En lugar de esperar hasta el día del lanzamiento para descubrir errores, CI los detecta inmediatamente.
Despliegue Continuo (CD) extiende CI desplegando automáticamente el código validado a entornos de staging o producción. Juntos, CI/CD crea un pipeline que lleva el código desde el commit hasta producción con mínima intervención manual.
Por qué importa: Los equipos que usan CI/CD lanzan más rápido, detectan errores antes y pasan menos tiempo en procesos de lanzamiento manuales. Un pipeline bien configurado puede reducir el tiempo de despliegue de horas a minutos.
Conceptos Fundamentales de GitHub Actions
Antes de escribir tu primer flujo de trabajo, entiende estos componentes básicos:
Workflows (Flujos de Trabajo)
Un workflow es un proceso automatizado definido en un archivo YAML dentro de .github/workflows/. Un repositorio puede tener múltiples workflows — uno para pruebas, otro para despliegue, y así sucesivamente.
Jobs (Trabajos)
Un workflow contiene uno o más jobs. Por defecto, los jobs se ejecutan en paralelo, pero puedes configurarlos para que se ejecuten secuencialmente usando dependencias.
Steps (Pasos)
Cada job contiene una serie de steps. Un step puede ejecutar un comando de shell o usar una action preconstruida del GitHub Marketplace.
Runners (Ejecutores)
Un runner es la máquina virtual que ejecuta tus jobs. GitHub proporciona runners alojados con Ubuntu, Windows y macOS. También puedes configurar runners auto-alojados para necesidades especializadas.
Actions (Acciones)
Las actions son unidades de código reutilizables. El GitHub Marketplace ofrece miles de actions creadas por la comunidad para tareas comunes como hacer checkout del código, configurar entornos de ejecución de lenguajes y desplegar en proveedores cloud.
Crear Tu Primer Flujo de Trabajo
Crea un archivo en .github/workflows/ci.yml en tu repositorio:
name: CI Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: npm ci
- name: Run linter
run: npm run lint
- name: Run tests
run: npm test
Este flujo de trabajo hace lo siguiente:
- Se activa en pushes a
mainodevelop, y en pull requests dirigidos amain - Se ejecuta en el runner Ubuntu más reciente
- Hace checkout del código de tu repositorio
- Configura Node.js versión 20
- Instala dependencias usando
npm ci(instalación limpia, más rápida y confiable quenpm install) - Ejecuta el linter y la suite de pruebas
Haz push de este archivo a tu repositorio y navega a la pestaña Actions para verlo ejecutarse.
Disparadores de Flujo de Trabajo
GitHub Actions soporta muchos eventos disparadores. Estos son los más comunes:
on:
# Disparar en push a ramas específicas
push:
branches: [main]
paths:
- 'src/**'
- 'package.json'
# Disparar en pull requests
pull_request:
branches: [main]
types: [opened, synchronize, reopened]
# Ejecuciones programadas (sintaxis cron)
schedule:
- cron: '0 6 * * 1' # Cada lunes a las 6 AM UTC
# Disparador manual desde la interfaz de GitHub
workflow_dispatch:
inputs:
environment:
description: 'Target environment'
required: true
default: 'staging'
type: choice
options:
- staging
- production
Consejo: Usa filtros
pathspara evitar ejecutar flujos de trabajo costosos cuando solo cambian archivos de documentación. Esto ahorra minutos de runner y acelera tu ciclo de retroalimentación.
Usar Actions Preconstruidas
La organización actions/ en GitHub proporciona actions esenciales:
steps:
# Hacer checkout de tu código
- uses: actions/checkout@v4
# Configurar varios entornos de ejecución de lenguajes
- uses: actions/setup-node@v4
with:
node-version: '20'
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- uses: actions/setup-go@v5
with:
go-version: '1.22'
# Subir artefactos de construcción
- uses: actions/upload-artifact@v4
with:
name: build-output
path: dist/
# Descargar artefactos de otro job
- uses: actions/download-artifact@v4
with:
name: build-output
Siempre fija las actions a una versión mayor específica (por ejemplo, @v4) para evitar cambios incompatibles inesperados.
Variables de Entorno y Secretos
Variables de Entorno
Define variables a nivel de workflow, job o step:
env:
NODE_ENV: production
API_URL: https://api.knowledgexchange.xyz
jobs:
build:
runs-on: ubuntu-latest
env:
DATABASE_URL: postgres://localhost:5432/testdb
steps:
- name: Print environment
run: echo "Building for $NODE_ENV"
env:
BUILD_NUMBER: ${{ github.run_number }}
Secretos
Nunca codifiques valores sensibles directamente. Almacénalos en Settings > Secrets and variables > Actions, luego referencíalos:
steps:
- name: Deploy to production
run: ./deploy.sh
env:
API_KEY: ${{ secrets.API_KEY }}
DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
Advertencia: Los secretos se enmascaran en los logs pero aún pueden ser expuestos accidentalmente. Nunca imprimas secretos directamente ni los escribas en archivos que se suban como artefactos.
Builds con Matrix
Prueba simultáneamente en múltiples versiones, sistemas operativos o configuraciones:
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [18, 20, 22]
fail-fast: false
steps:
- uses: actions/checkout@v4
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm test
Esto crea 9 jobs en paralelo (3 SO x 3 versiones de Node). Establecer fail-fast: false asegura que todas las combinaciones se ejecuten incluso si una falla, dándote una imagen completa de la compatibilidad.
Excluir e Incluir Combinaciones
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
node-version: [18, 20]
exclude:
- os: windows-latest
node-version: 18
include:
- os: ubuntu-latest
node-version: 22
experimental: true
Caché de Dependencias
Acelera los flujos de trabajo almacenando en caché las dependencias descargadas:
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm' # Soporte de caché integrado
- run: npm ci
Para más control, usa la action de caché directamente:
steps:
- name: Cache pip packages
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Install dependencies
run: pip install -r requirements.txt
La clave de caché se basa en el hash de tu archivo lock, por lo que el caché se invalida automáticamente cuando las dependencias cambian.
Construir y Subir Artefactos
Construye tu aplicación y guarda la salida para jobs posteriores o descarga:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run build
- name: Upload build artifact
uses: actions/upload-artifact@v4
with:
name: production-build
path: dist/
retention-days: 7
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- name: Download build artifact
uses: actions/download-artifact@v4
with:
name: production-build
path: dist/
- name: Deploy
run: echo "Deploying from dist/ directory"
La palabra clave needs: build asegura que el job de despliegue espere a que el job de construcción se complete exitosamente.
Ejemplo Práctico: Aplicación Node.js
Aquí tienes un pipeline CI/CD completo para una aplicación Node.js:
name: Node.js CI/CD
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
lint-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- name: Run ESLint
run: npm run lint
- name: Run unit tests
run: npm test -- --coverage
- name: Upload coverage report
if: github.event_name == 'pull_request'
uses: actions/upload-artifact@v4
with:
name: coverage-report
path: coverage/
build:
needs: lint-and-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 run build
- uses: actions/upload-artifact@v4
with:
name: build-output
path: dist/
deploy:
needs: build
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/download-artifact@v4
with:
name: build-output
path: dist/
- name: Deploy to Cloudflare Pages
uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: pages deploy dist/ --project-name=my-app
Ejemplo Práctico: Aplicación Python
name: Python CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.11', '3.12']
services:
postgres:
image: postgres:16
env:
POSTGRES_PASSWORD: testpassword
POSTGRES_DB: testdb
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
steps:
- uses: actions/checkout@v4
- name: Setup Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -r requirements-dev.txt
- name: Run flake8 linting
run: flake8 src/ --count --show-source --statistics
- name: Run pytest
run: pytest --cov=src --cov-report=xml
env:
DATABASE_URL: postgres://postgres:testpassword@localhost:5432/testdb
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
file: ./coverage.xml
token: ${{ secrets.CODECOV_TOKEN }}
Observa cómo este flujo de trabajo usa contenedores de servicio para levantar una base de datos PostgreSQL para pruebas de integración. GitHub Actions gestiona el ciclo de vida del contenedor automáticamente.
Desplegar un Sitio Estático en Vercel
name: Deploy to Vercel
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run build
- name: Deploy to Vercel
uses: amondnet/vercel-action@v25
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
vercel-args: '--prod'
working-directory: ./
Flujos de Trabajo Reutilizables
Evita duplicar lógica de flujos de trabajo entre repositorios creando flujos de trabajo reutilizables:
# .github/workflows/reusable-test.yml
name: Reusable Test Workflow
on:
workflow_call:
inputs:
node-version:
required: false
type: string
default: '20'
secrets:
npm-token:
required: false
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
cache: 'npm'
- run: npm ci
env:
NPM_TOKEN: ${{ secrets.npm-token }}
- run: npm test
Llámalo desde otro flujo de trabajo:
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main]
jobs:
test:
uses: ./.github/workflows/reusable-test.yml
with:
node-version: '20'
secrets:
npm-token: ${{ secrets.NPM_TOKEN }}
Ejecución Condicional y Salidas de Jobs
Controla cuándo se ejecutan steps y jobs usando condicionales:
jobs:
check:
runs-on: ubuntu-latest
outputs:
should-deploy: ${{ steps.changes.outputs.deploy }}
steps:
- uses: actions/checkout@v4
- name: Check for deployment-relevant changes
id: changes
run: |
if git diff --name-only HEAD~1 | grep -qE '^(src/|package\.json)'; then
echo "deploy=true" >> "$GITHUB_OUTPUT"
else
echo "deploy=false" >> "$GITHUB_OUTPUT"
fi
deploy:
needs: check
if: needs.check.outputs.should-deploy == 'true'
runs-on: ubuntu-latest
steps:
- run: echo "Deploying application..."
Mejores Prácticas
- Fija versiones de actions — Usa
@v4en lugar de@mainpara evitar roturas inesperadas - Usa
npm cien lugar denpm install— Es más rápido y asegura builds reproducibles - Habilita el caché — Almacena dependencias en caché para reducir drásticamente los tiempos de ejecución del flujo de trabajo
- Establece
fail-fast: falseen builds con matrix — Ve todos los fallos, no solo el primero - Usa environments — Define entornos
productionystagingcon puertas de aprobación - Mantén los secretos al mínimo — Solo otorga los permisos que tu flujo de trabajo realmente necesita
- Añade insignias de estado — Muestra el estado del build en tu README:

- Usa
concurrency— Cancela ejecuciones de flujo de trabajo redundantes cuando se hacen push de nuevos commits:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
Depurar Flujos de Trabajo Fallidos
Cuando un flujo de trabajo falla, usa estas técnicas:
- Revisa los logs en la pestaña Actions para el mensaje de error exacto
- Añade logging de depuración estableciendo el secreto
ACTIONS_STEP_DEBUGatrue - Usa
actpara ejecutar flujos de trabajo localmente:act -j test(requiere Docker) - Conéctate por SSH al runner para depuración interactiva usando
mxschmitt/action-tmate
- name: Debug with tmate
if: failure()
uses: mxschmitt/action-tmate@v3
timeout-minutes: 15
Resumen
GitHub Actions proporciona todo lo que necesitas para construir un pipeline CI/CD robusto sin salir de GitHub. Comienza con un simple flujo de trabajo de pruebas, luego añade gradualmente pasos de construcción, destinos de despliegue y pruebas con matrix. La clave es automatizar las tareas repetitivas que ralentizan a tu equipo — deja que las máquinas se encarguen de las pruebas y el despliegue para que los desarrolladores puedan enfocarse en escribir código.
Para más sobre mejores prácticas de programación y flujos de trabajo de desarrollo, explora nuestros artículos de Programación. Si estás desplegando en infraestructura cloud, consulta nuestras guías sobre hosting cloud y configuración de servidores.