GitHub Actions y GitLab CI/CD: automatización de pipelines y workflows
DevOps e infraestructura 2026-02-15 26 min de lectura

GitHub Actions y GitLab CI/CD: guía completa de automatización

Automatiza pruebas, builds y despliegues con GitHub Actions y GitLab CI/CD. Aprende workflows, pipelines, jobs, secretos y mejores prácticas en 2026.

Por CodeNaes

GitHub Actions y GitLab CI/CD: guía completa de automatización

GitHub Actions y GitLab CI/CD son dos de las plataformas de integración y despliegue continuos (CI/CD) más usadas. Ambas permiten definir pipelines que se ejecutan automáticamente al hacer push, abrir un pull request o según eventos que tú configures: tests, builds, publicar artefactos, desplegar en entornos, etc. En esta guía verás los conceptos clave de cada una, ejemplos prácticos, diferencias y buenas prácticas para febrero de 2026.

¿Qué es CI/CD?

CI (Integración Continua) consiste en integrar el código con frecuencia y comprobar automáticamente que no se rompa nada: tests unitarios, de integración, lint, build. CD (Entrega o Despliegue Continuo) lleva ese código validado hasta los entornos (staging, producción) de forma automatizada y repetible.

Un pipeline es la secuencia de pasos que se ejecutan: por ejemplo “instalar dependencias → lint → tests → build → desplegar”. Tanto GitHub Actions como GitLab CI/CD te permiten definir estos pipelines en archivos de configuración (YAML) dentro del repositorio.

GitHub Actions: conceptos básicos

GitHub Actions se configura con archivos workflow en .github/workflows/*.yml. Cada workflow tiene:

  • Eventos (triggers): cuándo se ejecuta (push, pull_request, schedule, workflow_dispatch, etc.).
  • Jobs: unidades de trabajo que corren en un runner (máquina virtual o self-hosted). Pueden depender unos de otros.
  • Steps: pasos dentro de un job; cada paso es un script o una acción (reusable).

Los runners por defecto son máquinas virtuales de GitHub (Linux, Windows, macOS). También puedes usar runners autohospedados en tu propia infraestructura.

Estructura de un workflow

name: CI

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

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
      - run: npm ci
      - run: npm run lint
      - run: npm test
  • on: eventos que disparan el workflow.
  • jobs.test: un job llamado test que corre en ubuntu-latest.
  • steps: checkout del repo, setup de Node con caché, instalación, lint y tests.

Eventos habituales

EventoUso típico
pushEjecutar CI en cada push a ciertas ramas.
pull_requestValidar cada PR (tests, lint, build).
workflow_dispatchEjecución manual desde la pestaña Actions.
schedule (cron)Tareas programadas (limpieza, reportes).
release: publishedPublicar artefactos o notificar al crear un release.

Acciones reutilizables y mercado

Las acciones son bloques reutilizables (propios del repo con uses: ./.github/actions/mi-accion o públicas desde GitHub Marketplace). Ejemplos muy usados:

  • actions/checkout@v4: clona el repositorio.
  • actions/setup-node@v4, actions/setup-python@v5: configuran runtime.
  • actions/cache@v4: cache de dependencias (npm, pip, etc.).
  • actions/upload-artifact@v4 y actions/download-artifact@v4: artefactos entre jobs.
  • actions/upload-pages-artifact@v4 y actions/deploy-pages@v4: despliegue en GitHub Pages.

Conviene fijar la versión de cada acción (por ejemplo @v4) o usar el commit SHA para mayor seguridad; revisa las releases para usar la última estable.

Secretos y variables

  • Secretos: Configuration → Secrets and variables → Actions. Se usan con ${{ secrets.MI_SECRETO }} y no se muestran en logs.
  • Variables: pueden ser de repositorio o de entorno; se referencian con ${{ vars.MI_VAR }}.

Usa secretos para tokens, API keys y credenciales; variables para configuración no sensible (entorno, rutas, flags).

Matriz de jobs

Para probar en varias versiones de Node o varios sistemas operativos:

jobs:
  test:
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest, windows-latest]
        node: ['20', '22']
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}
      - run: npm ci && npm test

Artefactos y caché

  • upload-artifact / download-artifact: pasar archivos (builds, reportes) entre jobs.
  • actions/cache: almacenar dependencias por clave (por ejemplo hash de package-lock.json) para acelerar runs.

Ejemplo: build y deploy en GitHub Pages

name: Build and Deploy

on:
  push:
    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 run build
      - uses: actions/upload-pages-artifact@v4
        with:
          path: ./dist

  deploy:
    needs: build
    runs-on: ubuntu-latest
    permissions:
      pages: write
      id-token: write
    environment: github-pages
    steps:
      - uses: actions/deploy-pages@4

El job deploy solo corre si build termina bien y usa el artefacto subido para publicar en GitHub Pages.


GitLab CI/CD: conceptos básicos

En GitLab la configuración vive en un único archivo (por defecto) .gitlab-ci.yml en la raíz del repo. Los conceptos equivalentes son:

  • Pipelines: una ejecución completa (como un workflow).
  • Stages: fases ordenadas (build, test, deploy). Los jobs se agrupan por stage.
  • Jobs: tareas que corren en un runner (GitLab.com o self-hosted).
  • Variables: definidas en el archivo, en la UI del proyecto o en grupos.

Los runners son agentes que ejecutan los jobs; GitLab ofrece runners compartidos en GitLab.com o puedes instalar los vuestros.

Estructura de un pipeline

stages:
  - install
  - lint
  - test
  - build

variables:
  NODE_VERSION: "20"

install:
  stage: install
  image: node:20-alpine
  script:
    - npm ci
  cache:
    key: ${CI_COMMIT_REF_SLUG}-npm
    paths:
      - node_modules
  artifacts:
    paths:
      - node_modules

lint:
  stage: lint
  image: node:20-alpine
  dependencies: []
  script:
    - npm ci
    - npm run lint

test:
  stage: test
  image: node:20-alpine
  script:
    - npm ci
    - npm test
  coverage: '/All files[^|]*\|[^|]*\s+([\d\.]+)/'

build:
  stage: build
  image: node:20-alpine
  script:
    - npm ci
    - npm run build
  artifacts:
    paths:
      - dist
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
  • stages: orden de ejecución (install → lint → test → build).
  • Cada job tiene stage, image (contenedor Docker), script y opcionalmente artifacts, cache y rules. En GitLab se recomienda usar rules en lugar de only/except, que están deprecados.

Imágenes Docker y servicios

Cada job puede especificar una image (contenedor base). Con services añades contenedores auxiliares (base de datos, Redis) para los tests:

test:
  image: node:20
  services:
    - postgres:15
  variables:
    POSTGRES_DB: test
    POSTGRES_USER: user
    POSTGRES_PASSWORD: pass
  script:
    - npm ci
    - npm run test:integration

Reglas: cuándo ejecutar un job

Con rules defines condiciones (ramas, variables, cambios en archivos) para ejecutar o no un job:

deploy_staging:
  stage: deploy
  script:
    - ./deploy.sh staging
  rules:
    - if: $CI_COMMIT_BRANCH == "develop"
    - if: $CI_PIPELINE_SOURCE == "web"

Solo se ejecuta en la rama develop o cuando el pipeline se lanza manualmente.

Variables predefinidas

GitLab inyecta muchas variables de entorno: CI_COMMIT_SHA, CI_COMMIT_REF_NAME, CI_COMMIT_BRANCH, CI_JOB_NAME, CI_PIPELINE_SOURCE, CI_PROJECT_PATH, CI_REGISTRY, CI_REGISTRY_IMAGE, etc. Son útiles en scripts y para condicionar jobs con rules.

Artefactos y caché

  • artifacts: archivos generados por un job que se pasan a jobs posteriores (o se descargan desde la UI). Puedes definir paths, expire_in, reports (JUnit, coverage). Por defecto un job recibe artefactos de todos los jobs de stages anteriores; con dependencies eliges de qué jobs recibirlos (o dependencies: [] para no recibir ninguno).
  • cache: entre pipelines para acelerar (por ejemplo node_modules o carpeta de dependencias).
  • needs: permite definir un grafo de dependencias entre jobs (no solo por stage), para ejecutar en paralelo cuando sea posible o acortar el pipeline.

Ejemplo: pipeline con deploy condicional

stages:
  - test
  - build
  - deploy

test:
  stage: test
  image: node:20-alpine
  script:
    - npm ci
    - npm run lint
    - npm test

build:
  stage: build
  image: node:20-alpine
  script:
    - npm ci
    - npm run build
  artifacts:
    paths:
      - dist
  rules:
    - if: $CI_COMMIT_BRANCH == "main"

deploy_production:
  stage: deploy
  script:
    - echo "Deploy to production"
    # e.g. rsync, kubectl, or your deploy tool
  environment: production
  rules:
    - if: $CI_COMMIT_BRANCH == "main"

Solo en main se hace build y deploy a producción.


Comparación rápida: GitHub Actions vs GitLab CI/CD

AspectoGitHub ActionsGitLab CI/CD
ConfiguraciónUno o más archivos en .github/workflows/*.ymlUn archivo .gitlab-ci.yml (o incluidos)
ModeloWorkflows con jobs y steps; acciones reutilizablesPipeline con stages y jobs; cada job con script
RunnersGitHub-hosted o self-hostedGitLab.com shared o self-hosted
EventosMuy granulado (push, pr, schedule, etc.)Principalmente por rama, tag, pipeline manual, API
SecretosRepo / env / org secretsVariables protegidas y masked
Mercado / reutilizaciónAcciones en Marketplace y en el repoPlantillas, includes, otros repos
EntornosEnvironments (approvals, secrets por env)Environments con protección y URLs
IntegraciónNativa con repos, issues, PRs de GitHubNativa con MRs, issues, registry de GitLab

Ambas son válidas para CI/CD completo; la elección suele depender de si ya usas GitHub o GitLab para el código y de las integraciones que necesites (registries, despliegues, notificaciones).


Runners autohospedados

Tanto GitHub como GitLab permiten usar runners en tu propia infraestructura cuando necesitas:

  • Control total del entorno (software preinstalado, GPU, acceso a redes internas).
  • Reducir coste o evitar límites de minutos (GitHub).
  • Cumplir políticas de seguridad que exigen que el código no salga de tu red.

GitHub: en Settings → Actions → Runners añades un runner (por repo u organización); el agente se instala en tu máquina o contenedor y se registra con un token. Los workflows pueden exigir ese runner con runs-on: [self-hosted, linux] (o la etiqueta que definas).

GitLab: en Settings → CI/CD → Runners instalas el GitLab Runner en tu servidor o Kubernetes; asignas el runner al proyecto o al grupo. En el job indicas la etiqueta con tags: [docker, production] para que solo ese runner ejecute ciertos jobs.

Usa runners autohospedados para jobs que requieran recursos específicos o que deban acceder a servicios internos; mantén el resto en runners gestionados si quieres menos mantenimiento.


Depuración y logs

  • GitHub Actions: cada run muestra los logs de cada step en la pestaña Actions. Puedes usar run: echo "::debug::mensaje" para salida de depuración (visible si activas debug logging con el secret ACTIONS_STEP_DEBUG). Los secretos aparecen ofuscados en los logs.
  • GitLab CI/CD: los logs del job se ven en la pestaña del pipeline; puedes descargar el log completo. Las variables masked no se muestran. Usa set -x en scripts para ver los comandos ejecutados o imprime variables no sensibles.

Si un job falla, revisa el step o la línea indicada; en GitLab comprueba también las rules por si el job no se está ejecutando donde esperas.


Seguridad

  • Fijar versiones de acciones (GitHub): usa etiquetas concretas (@v4) o el SHA del commit en lugar de @main para evitar que un cambio malintencionado en la acción afecte tus workflows. Dependabot puede proponerte actualizaciones de acciones.
  • Secretos y variables (GitLab): marca como masked las variables sensibles para que no aparezcan en los logs; usa protected para que solo se usen en ramas protegidas.
  • Permisos mínimos: en GitHub define permissions a nivel de workflow o de job (por ejemplo solo contents: read si no necesitas escribir en el repo). En GitLab limita qué variables y runners tienen acceso a datos sensibles.
  • Escaneo de dependencias: ambas plataformas ofrecen detección de vulnerabilidades en dependencias; actívala en la configuración del proyecto.

Buenas prácticas

  1. Cache de dependencias: usa actions/cache (GitHub) o cache en jobs (GitLab) con claves basadas en lockfiles para no reconstruir todo en cada run.
  2. Secretos: nunca los imprimas; en GitHub evita echo ${{ secrets.X }}; en GitLab marca variables como masked.
  3. Confinar permisos: en GitHub usa permissions por job (principle of least privilege); en GitLab revisa qué variables y runners ven los jobs.
  4. Matriz solo donde aporte: probar en 2–3 versiones de runtime suele bastar; no inflar la matriz sin necesidad.
  5. Fail rápido: en GitLab allow_failure solo donde tenga sentido; en GitHub continue-on-error con cuidado; configura notificaciones para fallos.
  6. Reutilizar: en GitHub crea acciones compuestas para pasos repetidos; en GitLab usa include o plantillas para no duplicar.
  7. Entornos y aprobaciones: para producción usa environments con aprobación manual (ambas plataformas) y secretos específicos del entorno.
  8. Límites y coste: en GitHub los minutos de runners tienen límites según plan; en GitLab revisa los minutos de runners compartidos. Optimiza duración de jobs para no gastar de más.

Resumen

  • GitHub Actions: workflows en YAML bajo .github/workflows/, disparados por eventos; jobs con steps que usan acciones o scripts; runners de GitHub o propios; ideal si tu código está en GitHub y quieres integración muy ligada a PRs y repos.
  • GitLab CI/CD: un pipeline definido en .gitlab-ci.yml con stages y jobs; cada job en un contenedor configurable; runners de GitLab o self-hosted; muy cómodo si ya usas GitLab para código, registry y despliegues.

Las dos permiten implementar CI/CD profesional: tests automáticos, builds, publicar artefactos y desplegar. Elegir una u otra depende de tu hosting de repos, del ecosistema (Marketplace vs includes/plantillas) y de si necesitas runners o entornos muy concretos. Con los ejemplos de esta guía puedes montar un pipeline básico en cualquiera de las dos y ampliarlo según tu stack (Node, Python, Docker, Kubernetes, etc.).

Documentación oficial (referencias):

Etiquetas:

github-actionsgitlab-cici-cddevopsautomatizaciónpipelinesworkflows