Cambiar tema

Introducción a GitHub Actions: fundamentos de flujos de trabajo YAML y configuración de disparadores

Easton editorial illustration: one large YAML workflow card driving three job stages

El error rojo en pantalla da ganas de tirar el teclado.

El código va bien en local y falla al hacer push a GitHub. Cambias el YAML seis veces y siempre es la indentación. ¿Por qué cuesta más que programar?

GitHub Actions en sí no es complejo. Lo difícil son docs de cientos de páginas de golpe. Este artículo explica la estructura central del flujo YAML de forma directa.

Aprenderás:

  • Los cuatro campos del YAML y qué hace cada uno
  • Cómo configurar 8 disparadores y cuándo usarlos
  • Una plantilla de flujo completa que puedes copiar
  • Trampas que yo pisé y cómo evitarlas

¿Listo? Empezamos.

Archivo de flujo YAML: cuatro campos clave

Al empezar con GitHub Actions, los YAML en .github/workflows parecían jeroglíficos: indentación, dos puntos, un espacio mal y todo falla.

Luego vi que son cuatro partes. Con esas cuatro, el resto es detalle.

name: nombre del flujo

El más simple; muchos (yo incluido) lo omiten al principio.

name: CI for Node.js App

name es lo que ves en la pestaña Actions de GitHub tras un push.

Truco: nombre del proyecto + función. Ej.: MyApp CI, Backend Deploy. Con muchos flujos, localizas rápido.

Se puede omitir; GitHub usa el nombre del archivo. No lo recomiendo: suele ser una abreviatura poco clara.

on: cuándo se dispara

8
Disparadores comunes
GitHub Actions admite decenas de disparadores; en proyectos reales los más usados son push, pull_request, schedule y workflow_dispatch

on es el «interruptor» del flujo: le dices a GitHub cuándo ejecutarlo.

Lo más simple:

on: push

Cualquier push lo activa.

En proyectos reales sueles acotar, p. ej. solo en main:

on:
  push:
    branches: [main]

O también al abrir o actualizar un Pull Request:

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

Los disparadores son el alma de Actions; más adelante veremos 8 escenarios. Por ahora: on define el momento de ejecución.

jobs: qué hay que hacer

jobs es el cuerpo del flujo: las tareas concretas.

Un flujo puede tener varios jobs en paralelo por defecto. Cada job necesita entorno con runs-on:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      # ...lista de pasos

Define un job build en la última Ubuntu que ofrece GitHub.

Con varios jobs, needs marca dependencias:

jobs:
  test:
    runs-on: ubuntu-latest
    # ... pasos de prueba

  deploy:
    needs: test  # Espera a que termine test
    runs-on: ubuntu-latest
    # ... pasos de despliegue

deploy arranca tras test. Si test falla, deploy no corre.

steps: pasos de ejecución

steps son la unidad mínima dentro de un job: comandos o Actions en orden.

Dos formas:

1. Con run (comando):

steps:
  - name: Install dependencies
    run: npm ci

  - name: Run tests
    run: npm test

run es el comando de terminal, como en local.

2. Con uses (Action):

steps:
  - name: Checkout code
    uses: actions/checkout@v4

  - name: Setup Node.js
    uses: actions/setup-node@v4
    with:
      node-version: '20'

uses reutiliza Actions de otros. actions/checkout@v4 clona el repo; actions/setup-node@v4 prepara Node.js.

with pasa parámetros; node-version: '20' pide Node.js 20.

Cuatro campos. ¿Más simple de lo que parecía?

Disparadores al detalle: 8 escenarios habituales

on fija el momento. Hay decenas de disparadores; en la práctica, pocos.

Tabla rápida:

DisparadorEscenario típicoEjemplo
pushPush a una ramaon: push: branches: [main]
pull_requestCrear o actualizar PRon: pull_request: types: [opened, synchronize]
scheduleTarea programada (Cron)on: schedule: - cron: '0 0 * * *'
workflow_dispatchDisparo manualon: workflow_dispatch: inputs: env: ...
workflow_callFlujo reutilizableon: workflow_call: inputs: ...
releaseEvento de releaseon: release: types: [published]
issuesEvento de issueon: issues: types: [opened, labeled]
repository_dispatchEvento externoon: repository_dispatch: types: [deploy]

Profundizamos en los más usados.

push: el disparador básico

Se activa al hacer push a una rama.

on: push

Problema: cualquier rama dispara el flujo. Con 20 ramas y muchos pushes, el minutaje gratis se agota pronto.

Mejor limitar ramas:

on:
  push:
    branches: [main, develop]

O con comodines:

on:
  push:
    branches:
      - 'main'
      - 'release/**'  # release/v1.0, release/v2.0, etc.

pull_request: guardián antes del merge

Al crear o actualizar un PR; típico para tests y estilo.

on:
  pull_request:
    branches: [main]

types acota el momento:

on:
  pull_request:
    types: [opened, synchronize, reopened]
  • opened: PR nuevo
  • synchronize: nuevos commits en el PR
  • reopened: PR reabierto

Solo en esos casos corre el flujo; ahorras minutos.

schedule: tareas programadas

Cron para ejecución periódica; p. ej. tests cada medianoche:

on:
  schedule:
    - cron: '0 0 * * *'  # Cada día a las 00:00 UTC

Cron tiene 5 campos: minuto, hora, día del mes, mes, día de la semana.

Ejemplos:

  • 0 0 * * *: diario a las 00:00 UTC (08:00 hora de Pekín)
  • 0 */6 * * *: cada 6 horas
  • 30 2 * * 1: lunes a las 02:30 UTC

Trampa: GitHub usa UTC. Para las 09:00 en Pekín, usa 01:00 UTC (0 1 * * *).

workflow_dispatch: disparo manual

A veces quieres un botón, no automatismo total. workflow_dispatch sirve para eso.

on:
  workflow_dispatch:
    inputs:
      environment:
        description: 'Entorno de despliegue'
        required: true
        default: 'staging'
        type: choice
        options:
          - staging
          - production

En Actions aparece «Run workflow» con parámetros. Muy útil: tests automáticos, despliegue manual.

workflow_call: flujo reutilizable

Lógica compleja o mismo flujo en varios repos: workflow_call lo convierte en componente.

Definir flujo reutilizable:

# .github/workflows/ci.yml
on:
  workflow_call:
    inputs:
      node-version:
        required: true
        type: string

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ inputs.node-version }}
      - run: npm ci && npm test

Invocarlo desde otro flujo:

# .github/workflows/main.yml
on: push

jobs:
  call-ci:
    uses: ./.github/workflows/ci.yml
    with:
      node-version: '20'

Misma lógica CI en varios repos; un cambio, todos actualizados.

Los demás (release, issues, repository_dispatch) se usan menos; consulta la documentación oficial si te interesan.

Práctica: tu primera plantilla de flujo

Mejor que teoría: un CI completo para Node.js. Cópialo tal cual:

name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      # 1. Clonar código
      - name: Checkout code
        uses: actions/checkout@v4

      # 2. Configurar Node.js
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'

      # 3. Instalar dependencias
      - name: Install dependencies
        run: npm ci

      # 4. Ejecutar tests
      - name: Run tests
        run: npm test

¿Cómo usarlo?

Paso 1: Crea .github/workflows en la raíz del proyecto (si no existe).

Paso 2: Crea ci.yml y pega el código.

Paso 3: Commit y push a GitHub.

Abre la pestaña Actions: el flujo debería estar corriendo.

Línea por línea

  • name: CI: nombre en Actions
  • on: push: branches: [main]: push a main
  • on: pull_request: branches: [main]: PR hacia main
  • jobs: build:: job llamado build
  • runs-on: ubuntu-latest: Ubuntu más reciente de GitHub
  • actions/checkout@v4: clona el repo en el runner
  • actions/setup-node@v4: configura Node.js
  • npm ci: instala dependencias (más rápido y limpio que npm install)
  • npm test: ejecuta tests

¿No es Node.js? Cambia los pasos del medio. Python:

steps:
  - uses: actions/checkout@v4
  - uses: actions/setup-python@v5
    with:
      python-version: '3.11'
  - run: pip install -r requirements.txt
  - run: pytest

Patrón: clonar → entorno → dependencias → tests.

Errores de configuración frecuentes

Trampas que yo pisé; espero que tú no.

Lista de comprobación:

SíntomaCausa probableSolución
El flujo no se disparaFiltro de ramas incorrectoRevisa branches y mayúsculas/minúsculas
Fallo al parsear YAMLIndentación con TabSolo espacios; YAML no admite Tab
Secrets no funcionanÁmbito incorrectoSecrets en el nivel correcto (job o step)
Falla dependencia de jobneeds mal referenciadoRevisa el id del job; distingue mayúsculas
Flujo muy lentoSin cachéAñade actions/cache para dependencias
Error de permisosGITHUB_TOKEN insuficienteAñade permissions en el job

Error 1: indentación incorrecta

El más común.

YAML exige espacios, no Tab. Cada nivel suele ser 2 espacios (en Actions, 2 es lo habitual).

# Mal: indentación rota
jobs:
  build:
  runs-on: ubuntu-latest  # Debería tener 4 espacios
# Bien
jobs:
  build:
    runs-on: ubuntu-latest  # 4 espacios

En VS Code o WebStorm activa «Tab inserta espacios».

Error 2: nombre de rama equivocado

Las ramas en GitHub distinguen mayúsculas. main y Main son distintas.

# Si tu rama es main
on:
  push:
    branches: [Main]  # Mal: no dispara

# Bien
on:
  push:
    branches: [main]

Si dudas, mira el repo en GitHub o ejecuta git branch en local.

Error 3: job-id mal escrito

Con varios jobs y needs, el id debe coincidir exactamente.

jobs:
  test:
    runs-on: ubuntu-latest
    # ...

  deploy:
    needs: Test  # Mal: mayúsculas no coinciden
    runs-on: ubuntu-latest
# Bien
jobs:
  test:
    runs-on: ubuntu-latest

  deploy:
    needs: test  # Igual que el id del job
    runs-on: ubuntu-latest

Error 4: Secrets en el nivel equivocado

Secrets a nivel de repositorio o de entorno. Referencia: ${{ secrets.XXX }}.

# Mal
jobs:
  build:
    runs-on: ubuntu-latest
    env:
      API_KEY: secrets.MY_KEY  # Falta ${{ }}
# Bien
jobs:
  build:
    runs-on: ubuntu-latest
    env:
      API_KEY: ${{ secrets.MY_KEY }}

Los secrets están cifrados; no ves el valor en logs. Para comprobar que llegó sin filtrarlo:

- name: Debug
  run: echo "API_KEY is set: ${{ secrets.MY_KEY != '' }}"

GitHub Actions frente a otras herramientas CI/CD

¿Jenkins, GitLab CI o CircleCI? Comparación rápida:

CriterioGitHub ActionsGitLab CIJenkinsCircleCI
Lenguaje de configYAMLYAMLGroovyYAML
AlojamientoCloud nativoCloud / self-hostedSelf-hostedCloud nativo
IntegraciónNativa en GitHubNativa en GitLabRequiere configRequiere config
Curva de aprendizajeBajaBajaAltaMedia
Cuota gratuita2000 min/mes (privados)400 min/mesIlimitado (self-hosted)6000 min/mes
Repos públicosIlimitadoIlimitadoIlimitadoIlimitado

Ventajas de GitHub Actions

1. Integración sin fricción

Si el código ya está en GitHub, Actions es lo más directo. Sin webhooks extra, sin servidor propio, sin plugins. Un YAML y push.

2. Ecosistema Marketplace

Miles de Actions; AWS, Azure y Google Cloud tienen oficiales. Lo que necesites, probablemente ya existe: solo uses.

3. Cuota amigable para individuos

Repos públicos ilimitados; privados 2000 min/mes. Para proyectos personales o equipos pequeños, suele bastar.

¿Cuándo no elegir GitHub Actions?

1. El código no está en GitHub

En GitLab o Bitbucket, usa su CI nativo. Actions con webhook es posible, pero más lío.

2. Necesitas control total del entorno

Los runners de GitHub son VMs fijas (Ubuntu/Windows/macOS). Software custom o entornos raros: Jenkins + self-hosted runner.

3. Requisitos de seguridad extremos

Runners son VMs de GitHub. Código muy sensible puede exigir CI propio. Self-hosted runner de GitHub es un término medio.

Mi recomendación

Para la mayoría de desarrolladores y equipos pequeños:

  • Código en GitHub → GitHub Actions
  • Código en GitLab → GitLab CI
  • Mucha personalización → Jenkins o self-hosted runner

No hay una única respuesta; la que encaje con tu caso.

Resumen

Ya tienes una idea clara del flujo YAML en GitHub Actions.

Puntos clave:

  • Cuatro campos: name, on, jobs, steps
  • Ocho disparadores habituales; los más usados: push, pull_request, schedule
  • Plantilla copiable: clonar → entorno → dependencias → tests
  • Cuatro trampas: indentación, rama, job-id, Secrets

Siguiente paso:

  1. Crea tu primer flujo (copia la plantilla y adáptala)
  2. Lee el artículo avanzado de la serie sobre caché en GitHub Actions para acelerar el pipeline
  3. Explora GitHub Marketplace por Actions útiles

La automatización, una vez que la pruebas, cuesta volver atrás.

FAQ

¿Qué campos debe incluir un flujo de GitHub Actions?
La configuración mínima solo necesita `on` (disparadores) y `jobs` (definición de tareas). `name` y `steps` son opcionales, pero conviene incluirlos para legibilidad.
¿Qué diferencia hay entre los disparadores push y pull_request?
`push` se activa al enviar código a una rama; encaja en despliegues. `pull_request` al crear o actualizar un PR; encaja en pruebas y revisión. Lo habitual: PR para tests, merge para despliegue.
¿Indentación con Tab o con espacios en YAML?
Solo espacios. YAML no admite Tab. En VS Code activa «Insertar espacios al pulsar Tab». Cada nivel suele usar 2 espacios.
¿Cuál es el límite gratuito y qué hacer si se agota?
Repos privados: 2000 minutos al mes; públicos: sin límite. Si te pasas, compra minutos extra o usa self-hosted runners (no cuentan en la cuota gratuita).

9 min de lectura · Publicado el: 10 abr 2026 · Actualizado el: 21 ago 2026

Comentarios

Inicia sesión con GitHub para dejar un comentario

Easton BlogEaston Blog