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.
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
testque corre enubuntu-latest. - steps: checkout del repo, setup de Node con caché, instalación, lint y tests.
Eventos habituales
| Evento | Uso típico |
|---|---|
push | Ejecutar CI en cada push a ciertas ramas. |
pull_request | Validar cada PR (tests, lint, build). |
workflow_dispatch | Ejecución manual desde la pestaña Actions. |
schedule (cron) | Tareas programadas (limpieza, reportes). |
release: published | Publicar 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@v4yactions/download-artifact@v4: artefactos entre jobs.actions/upload-pages-artifact@v4yactions/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),scripty opcionalmenteartifacts,cachey rules. En GitLab se recomienda usar rules en lugar deonly/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 (odependencies: []para no recibir ninguno). - cache: entre pipelines para acelerar (por ejemplo
node_moduleso 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
| Aspecto | GitHub Actions | GitLab CI/CD |
|---|---|---|
| Configuración | Uno o más archivos en .github/workflows/*.yml | Un archivo .gitlab-ci.yml (o incluidos) |
| Modelo | Workflows con jobs y steps; acciones reutilizables | Pipeline con stages y jobs; cada job con script |
| Runners | GitHub-hosted o self-hosted | GitLab.com shared o self-hosted |
| Eventos | Muy granulado (push, pr, schedule, etc.) | Principalmente por rama, tag, pipeline manual, API |
| Secretos | Repo / env / org secrets | Variables protegidas y masked |
| Mercado / reutilización | Acciones en Marketplace y en el repo | Plantillas, includes, otros repos |
| Entornos | Environments (approvals, secrets por env) | Environments con protección y URLs |
| Integración | Nativa con repos, issues, PRs de GitHub | Nativa 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 secretACTIONS_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 -xen 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@mainpara 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
permissionsa nivel de workflow o de job (por ejemplo solocontents: readsi 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
- Cache de dependencias: usa
actions/cache(GitHub) ocacheen jobs (GitLab) con claves basadas en lockfiles para no reconstruir todo en cada run. - Secretos: nunca los imprimas; en GitHub evita
echo ${{ secrets.X }}; en GitLab marca variables como masked. - Confinar permisos: en GitHub usa
permissionspor job (principle of least privilege); en GitLab revisa qué variables y runners ven los jobs. - Matriz solo donde aporte: probar en 2–3 versiones de runtime suele bastar; no inflar la matriz sin necesidad.
- Fail rápido: en GitLab
allow_failuresolo donde tenga sentido; en GitHubcontinue-on-errorcon cuidado; configura notificaciones para fallos. - Reutilizar: en GitHub crea acciones compuestas para pasos repetidos; en GitLab usa
includeo plantillas para no duplicar. - Entornos y aprobaciones: para producción usa environments con aprobación manual (ambas plataformas) y secretos específicos del entorno.
- 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.ymlcon 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):