Cada flujo de trabajo de GitHub Actions que has escrito es un archivo YAML. Todo — los disparadores, los jobs, los pasos, las variables de entorno, la estrategia matrix — se expresa en YAML. Lo que significa que entender YAML profundamente no es solo académico: es la diferencia entre una CI que funciona de forma fiable y una CI que falla misteriosamente a las 4pm de un viernes cuando intentas publicar una versión.

GitHub Actions tiene excelente documentación de sintaxis de workflows, pero se centra en las características de Actions en lugar de los mecanismos YAML subyacentes. Este artículo cubre ambos — la estructura del workflow, y los patrones YAML específicos (y las trampas) que hacen o deshacen las configuraciones de CI.

Estructura del workflow: las claves de nivel superior

Un archivo de workflow de GitHub Actions vive en .github/workflows/ y tiene tres claves obligatorias de nivel superior. La descripción general oficial de workflows explica dónde reside el archivo en tu repositorio y cómo GitHub lo descubre:

yaml
name: CI Pipeline          # optional but shown in the Actions UI

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

jobs:                      # the actual work
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci && npm test
Cuidado con on como booleano YAML: En YAML 1.1, la palabra sola on se interpreta como el booleano true. El parser de GitHub maneja esto correctamente, pero si alguna vez ves tu archivo de workflow marcado por un linter YAML genérico, es por esto. La forma segura es entrecomillarlo: "on": — aunque GitHub Actions en sí mismo no requiere las comillas.

Disparadores: la clave on:

La clave on: controla cuándo se ejecuta tu workflow. La lista completa de eventos disparadores cubre todo, desde revisiones de pull request hasta despachos de repositorio. Aquí están los patrones más comunes:

yaml
on:
  # Push to specific branches
  push:
    branches:
      - main
      - "release/**"       # glob pattern — quotes needed for /**
    paths-ignore:
      - "docs/**"
      - "*.md"

  # PRs targeting main
  pull_request:
    branches: [main]
    types: [opened, synchronize, reopened]

  # Scheduled (cron syntax)
  schedule:
    - cron: "0 2 * * 1"   # every Monday at 2am UTC

  # Manual trigger with input
  workflow_dispatch:
    inputs:
      environment:
        description: "Target environment"
        required: true
        default: staging
        type: choice
        options: [staging, production]

Comandos run: multilínea y bloques escalares YAML

La clave run: es donde el bloque escalar literal de YAML (|) demuestra su valor — consulta la referencia yaml-multiline.info para cada variación de bloques y escalares plegados. Sin él, encadenarías comandos con && en una sola línea, lo cual es ilegible:

yaml
steps:
  # Single line — works but hard to read
  - name: Build
    run: npm ci && npm run lint && npm run test && npm run build

  # Multi-line with literal block scalar — much better
  - name: Build
    run: |
      npm ci
      npm run lint
      npm run test -- --coverage
      npm run build

  # Folded scalar (>) joins lines with spaces — NOT what you want for shell
  # This would run as a single command with spaces where the newlines are:
  - name: Wrong for shell
    run: >
      npm ci
      npm test
Usa siempre | para scripts shell multilínea, nunca >. El escalar plegado colapsa los saltos de línea en espacios, lo que significa que tus comandos shell se unen en una larga cadena. Eso causa errores crípticos. El bloque escalar literal | preserva exactamente los saltos de línea, por lo que cada línea se ejecuta como un comando shell separado.

Variables de entorno y secretos

Las variables de entorno en GitHub Actions usan YAML en combinación con el contexto de Actions y la sintaxis de expresión. Así es como encajan:

yaml
env:
  NODE_ENV: production         # workflow-level env var
  API_VERSION: "2.1"          # quoted to force string type

jobs:
  deploy:
    runs-on: ubuntu-latest
    env:
      DEPLOY_ENV: staging      # job-level env var (overrides workflow-level)

    steps:
      - name: Deploy to staging
        env:
          API_KEY: ${{ secrets.STAGING_API_KEY }}     # step-level, from secret
          DATABASE_URL: ${{ vars.STAGING_DB_URL }}    # step-level, from variable
        run: |
          echo "Deploying to $DEPLOY_ENV"
          ./scripts/deploy.sh

La sintaxis de expresión ${{ }} es el propio lenguaje de plantilla de GitHub Actions superpuesto sobre YAML. Se evalúa antes del análisis YAML en algunos contextos, lo que puede interactuar inesperadamente con las propias reglas de comillas de YAML. En caso de duda, envuelve los valores que comienzan con ${{ entre comillas dobles.

Estrategia matrix: construir con múltiples configuraciones

La estrategia matrix es una de las características más poderosas de GitHub Actions — y se expresa completamente en YAML. Ejecuta tu job una vez por cada combinación de valores matrix:

yaml
jobs:
  test:
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false         # don't cancel other matrix jobs on failure
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
        node: ["18", "20", "22"]
        exclude:
          - os: windows-latest
            node: "18"         # skip this combination

    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}
      - run: npm ci && npm test

Esta única definición de job produce hasta 9 ejecuciones paralelas (3 SO × 3 versiones Node, menos 1 excluida). Los valores matrix YAML son arreglos simples — lo único que hay que vigilar es que los números de versión como 18 deben estar entrecomillados como "18" para mantenerlos como cadenas. Sin comillas, YAML los analiza como enteros y algunas Actions pueden quejarse.

Pasos condicionales con if:

La clave if: te permite omitir pasos según condiciones. Usa el lenguaje de expresión de GitHub, no valores YAML simples:

yaml
steps:
  - name: Run tests
    run: npm test

  - name: Upload coverage
    if: success() && github.ref == 'refs/heads/main'
    uses: codecov/codecov-action@v4

  - name: Notify on failure
    if: failure()
    uses: slackapi/slack-github-action@v1
    with:
      slack-message: "Build failed on ${{ github.ref }}"
      channel-id: "C12345ABC"
    env:
      SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}

  - name: Deploy (only on tag push)
    if: startsWith(github.ref, 'refs/tags/v')
    run: ./scripts/deploy.sh production

Workflows reutilizables

Para eliminar la duplicación entre repositorios (no solo dentro de un archivo), GitHub Actions soporta los workflows reutilizables. El workflow llamado usa on: workflow_call: y el llamante usa uses: al nivel del job — no al nivel del paso:

yaml
# .github/workflows/reusable-test.yml (the reusable workflow)
on:
  workflow_call:
    inputs:
      node-version:
        required: false
        type: string
        default: "20"
    secrets:
      NPM_TOKEN:
        required: true

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
        env:
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
yaml
# .github/workflows/ci.yml (the caller)
on: [push, pull_request]

jobs:
  run-tests:
    uses: my-org/shared-workflows/.github/workflows/reusable-test.yml@main
    with:
      node-version: "22"
    secrets:
      NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

Los errores YAML más comunes en GitHub Actions

  • Indentación incorrecta en los pasos. Los pasos deben estar indentados bajo steps: con espacios consistentes. Un espacio de más o de menos saca un paso fuera de su job.
  • Números de versión sin comillas. node-version: 20 pasa un entero; algunas actions esperan una cadena. Usa node-version: "20" para mayor seguridad.
  • Usar > en lugar de | para scripts shell. Los escalares plegados colapsan los saltos de línea. Tu script multilínea se convierte en una larga cadena y falla.
  • Comillas faltantes en patrones glob. Patrones como release/** contienen * que YAML puede interpretar como un alias. Siempre pon entre comillas los patrones glob.
  • Secretos usados en condiciones if:. GitHub enmascara los secretos en los registros pero no los permite en expresiones if:. Usa una variable de entorno en su lugar.
  • Olvidar fail-fast: false en jobs matrix. Por defecto, si un job matrix falla, todos los demás se cancelan. Generalmente no es lo que quieres durante la depuración.

Conclusión

Los workflows de GitHub Actions son fundamentalmente archivos YAML — entender los bloques escalares literales de YAML, las reglas de comillas y la coerción de tipos se traduce directamente en escribir una CI más fiable. Los fallos más comunes provienen de errores de indentación, valores sin comillas que se coercionan al tipo incorrecto, y usar el operador de cadena multilínea incorrecto para scripts shell. Domina esas tres cosas y la mayoría de la depuración de workflows se vuelve sencilla. Usa el Validador YAML para detectar errores de sintaxis antes de hacer push, y el Formateador YAML para aplicar indentación consistente en tus archivos de workflow.