guias·14 min de lectura

CI/CD con GitHub Actions para Next.js: Pipeline Completo

Guia paso a paso para configurar CI/CD con GitHub Actions en tu proyecto Next.js. Linting, testing, build y deploy automatico a Vercel con cada push.

CI/CD con GitHub Actions para Next.js: Pipeline Completo

Configurar CI/CD con GitHub Actions para tu proyecto Next.js es una de esas cosas que parece compleja hasta que la haces una vez. Despues no entiendes como vivias sin ella. Cada push a tu repo dispara automaticamente linting, tests y build. Si algo falla, te enteras antes de que llegue a produccion. Si todo pasa, deploya solo.

Esta guia te lleva desde cero hasta un pipeline completo. No importa si nunca tocaste un archivo YAML de GitHub Actions. Vamos paso a paso.

Por que tu proyecto necesita CI/CD

Sin CI/CD, el flujo tipico es: escribes codigo, haces push, cruzas los dedos y deployeas manualmente. Si tienes suerte, funciona. Si no, descubres el bug en produccion cuando un usuario te reporta algo.

Con CI/CD, el flujo cambia completamente:

  1. Haces push o abres un pull request
  2. GitHub Actions automaticamente corre ESLint, los tests y el build
  3. Si algo falla, el PR se marca como fallido y no se puede mergear
  4. Si todo pasa, deploya automaticamente a produccion

Las ventajas concretas:

  • Detectas errores antes: Un error de TypeScript que pasa en tu maquina no pasa en CI porque la configuracion es estricta
  • Consistencia: No importa quien haga el push, las mismas validaciones corren siempre
  • Confianza: Si el pipeline paso, sabes que el codigo compila, pasa los tests y el build funciona
  • Historial: Cada run queda registrado. Si algo se rompe, puedes ver exactamente que commit lo causo

Requisitos previos

Antes de empezar, necesitas:

  1. Un proyecto Next.js funcionando en local (npm run dev sin errores)
  2. Un repositorio en GitHub con tu proyecto pusheado
  3. ESLint configurado (Next.js lo incluye por defecto con create-next-app)

No necesitas experiencia previa con YAML ni con GitHub Actions. Todo lo que necesitas saber de YAML lo vas a aprender aqui.

ℹ️
Si ya tienes deploy en Vercel

Si tu proyecto ya esta deployado en Vercel, la parte de CD (deploy automatico) ya la tienes resuelta. Esta guia te ayuda a agregar la parte de CI: linting, tests y build verification como checks obligatorios antes de mergear.

Tu primer workflow: lint automatico

Un workflow de GitHub Actions es un archivo YAML que vive en .github/workflows/ dentro de tu repositorio. Vamos a crear el mas basico posible: correr ESLint en cada push.

Crear el archivo

Estructura de archivos

tu-proyecto/ ├── .github/ │ └── workflows/ │ └── ci.yml ├── app/ ├── components/ ├── package.json └── next.config.ts

Crea el archivo .github/workflows/ci.yml con este contenido:

yaml
# .github/workflows/ci.yml
name: CI
 
# Cuando se ejecuta este workflow
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
 
jobs:
  lint:
    # Maquina donde corre el job
    runs-on: ubuntu-latest
 
    steps:
      # Paso 1: Clonar el repositorio
      - name: Checkout codigo
        uses: actions/checkout@v4
 
      # Paso 2: Configurar Node.js
      - name: Configurar Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20
 
      # Paso 3: Instalar dependencias
      - name: Instalar dependencias
        run: npm ci
 
      # Paso 4: Correr ESLint
      - name: Lint
        run: npm run lint

Que hace cada parte

  • name: CI: El nombre que aparece en la interfaz de GitHub
  • on: Define cuando se dispara el workflow. En este caso, en cada push a main y en cada pull request hacia main
  • jobs: Los trabajos que se ejecutan. Un workflow puede tener multiples jobs
  • runs-on: ubuntu-latest: La maquina virtual donde corre. Ubuntu es la opcion mas comun y rapida
  • steps: Los pasos dentro del job. Se ejecutan en orden
  • npm ci: Similar a npm install pero mas rapido y determinista. Usa el package-lock.json exacto sin modificarlo
💡
npm ci vs npm install

Siempre usa npm ci en CI/CD. A diferencia de npm install, no modifica el package-lock.json y falla si hay inconsistencias. Esto garantiza que en CI se instalan exactamente las mismas versiones que en tu maquina local.

Verificar que funciona

Commitea el archivo y pushea:

Terminal
$

Ve a tu repositorio en GitHub > pestaña Actions. Vas a ver tu workflow corriendo. Si ESLint pasa, el check se marca en verde. Si falla, en rojo con los errores en los logs.

Agregar tests al pipeline

Un linter detecta problemas de estilo y errores obvios, pero no verifica que tu logica funcione. Para eso necesitas tests. Vamos a configurar Vitest y agregarlo al workflow.

Configurar Vitest

Terminal
$

Crea el archivo de configuracion:

typescript
// vitest.config.ts
import { defineConfig } from 'vitest/config'
import react from '@vitejs/plugin-react'
import path from 'path'
 
export default defineConfig({
  plugins: [react()],
  test: {
    environment: 'jsdom',
    setupFiles: ['./vitest.setup.ts'],
    globals: true,
  },
  resolve: {
    alias: {
      '@': path.resolve(__dirname, '.'),
    },
  },
})
typescript
// vitest.setup.ts
import '@testing-library/jest-dom/vitest'

Agrega el script en tu package.json:

json
{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "lint": "next lint",
    "test": "vitest run",
    "test:watch": "vitest"
  }
}

Escribir un test basico

typescript
// __tests__/utils.test.ts
import { describe, it, expect } from 'vitest'
 
// Ejemplo: una funcion que formatea fechas
function formatearFecha(fecha: string): string {
  return new Date(fecha).toLocaleDateString('es-MX', {
    year: 'numeric',
    month: 'long',
    day: 'numeric',
  })
}
 
describe('formatearFecha', () => {
  it('formatea una fecha ISO correctamente', () => {
    const resultado = formatearFecha('2026-03-03')
    expect(resultado).toContain('marzo')
    expect(resultado).toContain('2026')
  })
 
  it('maneja fechas invalidas', () => {
    const resultado = formatearFecha('no-es-una-fecha')
    expect(resultado).toBe('Invalid Date')
  })
})

Agregar el step de test al workflow

Actualiza el archivo ci.yml para incluir un job de test:

yaml
# .github/workflows/ci.yml
name: CI
 
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
 
jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout codigo
        uses: actions/checkout@v4
 
      - name: Configurar Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20
 
      - name: Instalar dependencias
        run: npm ci
 
      - name: Lint
        run: npm run lint
 
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout codigo
        uses: actions/checkout@v4
 
      - name: Configurar Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20
 
      - name: Instalar dependencias
        run: npm ci
 
      - name: Tests
        run: npm run test
ℹ️
Jobs en paralelo

Por defecto, los jobs de un workflow corren en paralelo. Lint y test se ejecutan al mismo tiempo en maquinas separadas, lo que reduce el tiempo total del pipeline.

Build verification

El linter pasa y los tests pasan, pero eso no garantiza que next build funcione. TypeScript puede tener errores que solo aparecen durante el build, o puedes tener imports rotos que no se detectan en dev mode.

Agrega un job de build al workflow:

yaml
  build:
    runs-on: ubuntu-latest
    # Solo correr si lint y test pasaron
    needs: [lint, test]
    steps:
      - name: Checkout codigo
        uses: actions/checkout@v4
 
      - name: Configurar Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20
 
      - name: Instalar dependencias
        run: npm ci
 
      - name: Build
        run: npm run build

La clave aqui es needs: [lint, test]. Esto le dice a GitHub Actions que el job de build solo corra si lint y test pasaron primero. No tiene sentido intentar el build si el linter encontro errores.

El flujo queda asi:

plaintext
push / PR
  ├── lint ─────┐
  └── test ─────┤
                └── build (solo si ambos pasaron)

Cachear dependencias para pipelines rapidos

Cada vez que corre el workflow, instala todas las dependencias desde cero. En un proyecto Next.js tipico, eso toma entre 30 segundos y 2 minutos. Multiplicado por tres jobs, es tiempo desperdiciado.

La solucion es cachear node_modules entre runs:

yaml
  lint:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout codigo
        uses: actions/checkout@v4
 
      - name: Configurar Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'npm'
 
      - name: Instalar dependencias
        run: npm ci
 
      - name: Lint
        run: npm run lint

El cambio es una sola linea: cache: 'npm' en el step de setup-node. GitHub Actions cachea automaticamente el directorio de cache de npm. Si el package-lock.json no cambio, las dependencias se restauran del cache en segundos.

💡
Impacto del cache

En un proyecto Next.js tipico, el cache reduce el tiempo de instalacion de dependencias de 40-90 segundos a 3-5 segundos. En un pipeline con tres jobs, eso son entre 2 y 4 minutos ahorrados por cada run.

Cache avanzado: el store de Next.js

Next.js tiene su propio cache de build (.next/cache) que acelera builds subsecuentes. Puedes cachearlo tambien:

yaml
      - name: Cache de Next.js
        uses: actions/cache@v4
        with:
          path: ${{ github.workspace }}/.next/cache
          # Regenerar cache cuando cambian dependencias o archivos de config
          key: nextjs-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**/*.ts', '**/*.tsx') }}
          restore-keys: |
            nextjs-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}-
            nextjs-${{ runner.os }}-

Esto puede reducir el tiempo de build de 60 segundos a 15-20 en builds incrementales.

Pull request checks: proteger tu rama principal

De nada sirve tener CI si alguien puede mergear un PR sin que pasen los checks. GitHub te permite configurar branch protection rules para hacer los checks obligatorios.

Configurar branch protection

  1. Ve a tu repositorio en GitHub > Settings > Branches
  2. Haz clic en Add branch protection rule
  3. En "Branch name pattern" escribe main
  4. Activa Require status checks to pass before merging
  5. Busca y selecciona tus checks: lint, test, build
  6. Activa Require branches to be up to date before merging
  7. Guarda los cambios

A partir de ahora, nadie puede mergear un PR a main si alguno de los checks falla. El boton de merge en GitHub se bloquea hasta que todo este en verde.

⚠️
Primer run necesario

Los checks no aparecen en la lista hasta que el workflow haya corrido al menos una vez. Pushea el archivo ci.yml primero, espera a que complete, y despues configura las branch protection rules.

Que ve el equipo en un PR

Cuando alguien abre un PR, GitHub muestra el estado de cada check:

plaintext
Checks:
  ✓ lint        — Passed in 45s
  ✓ test        — Passed in 1m 12s
  ✓ build       — Passed in 2m 3s
 
✓ All checks have passed

Si algo falla:

plaintext
Checks:
  ✓ lint        — Passed in 45s
  ✗ test        — Failed in 38s
  ○ build       — Skipped (needs test)
 
✗ Some checks were not successful

El autor del PR ve los logs del error directamente en GitHub y puede corregir sin que nadie tenga que revisar codigo roto.

Deploy automatico con Vercel

Si ya tienes tu proyecto deployado en Vercel, el deploy automatico ya esta funcionando: cada push a main dispara un deploy a produccion, y cada PR genera un preview deployment.

Lo que puedes agregar con GitHub Actions es un paso adicional que corra tus validaciones antes de que Vercel haga el deploy. Asi te aseguras de que el deploy solo ocurra si CI pasa.

Opcion 1: Vercel + GitHub Actions en paralelo

La configuracion mas comun. Vercel sigue manejando los deploys, y GitHub Actions maneja las validaciones:

plaintext
PR abierto
  ├── GitHub Actions: lint, test, build (CI)
  └── Vercel: preview deployment (CD)
 
Merge a main
  ├── GitHub Actions: lint, test, build (CI)
  └── Vercel: production deployment (CD)

No necesitas configurar nada extra. Vercel y GitHub Actions corren en paralelo automaticamente.

Opcion 2: Deploy controlado por GitHub Actions

Si necesitas control total y quieres que el deploy solo ocurra si CI pasa, puedes usar la Vercel CLI desde GitHub Actions:

yaml
  deploy:
    runs-on: ubuntu-latest
    needs: [lint, test, build]
    # Solo deployar en push a main (no en PRs)
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    steps:
      - name: Checkout codigo
        uses: actions/checkout@v4
 
      - name: Configurar Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'npm'
 
      - name: Instalar Vercel CLI
        run: npm install -g vercel
 
      - name: Deploy a produccion
        run: vercel --prod --token=${{ secrets.VERCEL_TOKEN }}
        env:
          VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
          VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}

Para esta opcion necesitas agregar tres secrets en tu repositorio:

  1. VERCEL_TOKEN: Lo generas en vercel.com/account/tokens
  2. VERCEL_ORG_ID: Lo encuentras en Vercel > Settings > General
  3. VERCEL_PROJECT_ID: Lo encuentras en Vercel > tu proyecto > Settings > General

Alternativa: deploy a otras plataformas

GitHub Actions puede deployar a cualquier plataforma. Si usas Railway o DigitalOcean, el step de deploy cambia pero el pipeline de CI sigue igual:

yaml
  # Ejemplo: deploy a Railway
  deploy:
    runs-on: ubuntu-latest
    needs: [lint, test, build]
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    steps:
      - name: Checkout codigo
        uses: actions/checkout@v4
 
      - name: Deploy a Railway
        uses: bervProject/railway-deploy@main
        with:
          railway_token: ${{ secrets.RAILWAY_TOKEN }}
          service: tu-servicio
ℹ️
La parte de CI no cambia

El pipeline de CI (lint, test, build) es identico sin importar donde hagas deploy. Lo unico que cambia es el job final de deployment. Esto te da la libertad de migrar entre plataformas sin reescribir tu pipeline de validacion.

Avanzado: matrix strategy

Matrix strategy te permite correr el mismo job con diferentes configuraciones. El caso de uso mas comun es probar tu proyecto en multiples versiones de Node.js:

yaml
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [18, 20, 22]
    steps:
      - name: Checkout codigo
        uses: actions/checkout@v4
 
      - name: Configurar Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: 'npm'
 
      - name: Instalar dependencias
        run: npm ci
 
      - name: Tests
        run: npm run test

Esto crea tres jobs que corren en paralelo, uno por cada version de Node.js. Si tu proyecto soporta Node 18, 20 y 22, verificas que funcione en las tres con un solo cambio.

Cuando usar matrix strategy

  • Librerias o paquetes npm: Para garantizar compatibilidad con multiples versiones de Node.js
  • Proyectos con multiples package managers: Probar con npm, yarn y pnpm
  • Testing cross-OS: Probar en Ubuntu, macOS y Windows

Cuando NO usarla

Para la mayoria de aplicaciones Next.js, probar en una sola version de Node.js es suficiente. La matrix strategy aumenta el consumo de minutos. Si tu proyecto solo corre en produccion con Node 20, no necesitas probar en Node 18.

Avanzado: manejo de secrets y variables de entorno

Tu pipeline de CI probablemente necesita variables de entorno para funcionar. El build de Next.js puede necesitar NEXT_PUBLIC_SITE_URL, y tus tests pueden necesitar conexion a una base de datos de prueba.

Agregar secrets en GitHub

  1. Ve a tu repositorio > Settings > Secrets and variables > Actions
  2. Haz clic en New repository secret
  3. Escribe el nombre y el valor

Los secrets se encriptan y nunca se muestran en los logs, ni siquiera si haces echo $SECRET en un step.

Usar secrets en el workflow

yaml
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout codigo
        uses: actions/checkout@v4
 
      - name: Configurar Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'npm'
 
      - name: Instalar dependencias
        run: npm ci
 
      - name: Build
        run: npm run build
        env:
          NEXT_PUBLIC_SITE_URL: ${{ secrets.NEXT_PUBLIC_SITE_URL }}
          DATABASE_URL: ${{ secrets.DATABASE_URL }}

Variables de entorno vs secrets

GitHub Actions distingue entre variables y secrets:

TipoEncriptadoVisible en logsUso
SecretsSiNuncaAPI keys, tokens, passwords
VariablesNoSiURLs publicas, flags de configuracion

Las variables se configuran en Settings > Secrets and variables > Actions > Variables y se acceden con vars.NOMBRE:

yaml
      - name: Build
        run: npm run build
        env:
          NEXT_PUBLIC_SITE_URL: ${{ vars.SITE_URL }}
          API_SECRET: ${{ secrets.API_SECRET }}
⚠️
Secrets en forks

Si tu repositorio es publico y alguien abre un PR desde un fork, los secrets no estan disponibles en ese workflow por seguridad. Esto previene que alguien modifique el workflow para imprimir tus secrets. Los PRs de forks solo tienen acceso a variables publicas.

Seguridad del pipeline

Ademas de manejar secrets correctamente, considera agregar un step de seguridad a tu pipeline. Herramientas como datahogo pueden integrarse como step de CI para detectar secrets expuestos en tu codigo antes de que lleguen a produccion. Si tu repositorio ya esta conectado a datahogo, lo detecta automaticamente en cada PR.

Tambien puedes correr npm audit como parte del pipeline para detectar vulnerabilidades en dependencias:

yaml
      - name: Auditoria de seguridad
        run: npm audit --audit-level=high

Si necesitas un enfoque mas completo de seguridad, revisa la guia de seguridad en aplicaciones Next.js.

Workflow completo

Este es el archivo ci.yml final con todas las piezas juntas: lint, test, build, cache, y deploy condicional:

yaml
# .github/workflows/ci.yml
name: CI/CD
 
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
 
# Cancelar runs anteriores del mismo PR para no desperdiciar minutos
concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true
 
jobs:
  lint:
    name: Lint
    runs-on: ubuntu-latest
    steps:
      - name: Checkout codigo
        uses: actions/checkout@v4
 
      - name: Configurar Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'npm'
 
      - name: Instalar dependencias
        run: npm ci
 
      - name: ESLint
        run: npm run lint
 
  test:
    name: Tests
    runs-on: ubuntu-latest
    steps:
      - name: Checkout codigo
        uses: actions/checkout@v4
 
      - name: Configurar Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'npm'
 
      - name: Instalar dependencias
        run: npm ci
 
      - name: Vitest
        run: npm run test
 
  build:
    name: Build
    runs-on: ubuntu-latest
    needs: [lint, test]
    steps:
      - name: Checkout codigo
        uses: actions/checkout@v4
 
      - name: Configurar Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'npm'
 
      - name: Instalar dependencias
        run: npm ci
 
      - name: Cache de Next.js
        uses: actions/cache@v4
        with:
          path: ${{ github.workspace }}/.next/cache
          key: nextjs-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**/*.ts', '**/*.tsx') }}
          restore-keys: |
            nextjs-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}-
            nextjs-${{ runner.os }}-
 
      - name: Build
        run: npm run build
        env:
          NEXT_PUBLIC_SITE_URL: ${{ vars.SITE_URL }}
 
  deploy:
    name: Deploy
    runs-on: ubuntu-latest
    needs: [build]
    # Solo deployar en push a main
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    steps:
      - name: Checkout codigo
        uses: actions/checkout@v4
 
      - name: Configurar Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'npm'
 
      - name: Instalar Vercel CLI
        run: npm install -g vercel
 
      - name: Deploy a produccion
        run: vercel --prod --token=${{ secrets.VERCEL_TOKEN }}
        env:
          VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
          VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}

Detalles importantes del workflow

concurrency: Cancela runs anteriores del mismo PR cuando haces un push nuevo. Si pusheas tres commits rapido, solo el ultimo run completa. Esto ahorra minutos de GitHub Actions.

needs: [lint, test]: El build solo corre si lint y test pasaron. No desperdicias minutos en un build que ya sabes que va a fallar.

if: github.event_name == 'push': El deploy solo corre en push directo a main, no en pull requests. Los PRs solo corren lint, test y build para validacion.

Estructura visual del pipeline

plaintext
Pull Request:
  ├── lint (paralelo)
  ├── test (paralelo)
  └── build (despues de lint + test)
 
Push a main:
  ├── lint (paralelo)
  ├── test (paralelo)
  ├── build (despues de lint + test)
  └── deploy (despues de build)

Debugging: cuando tu pipeline falla

Error: "npm ci" falla

plaintext
npm ERR! `npm ci` can only install packages when your package-lock.json
npm ERR! is up-to-date

Causa: Tu package-lock.json no esta sincronizado con package.json.

Solucion: Corre npm install en local, commitea el package-lock.json actualizado y pushea.

Terminal
$

Error: ESLint falla en CI pero no en local

Causa comun: Diferencia en versiones de Node.js o reglas mas estrictas en CI.

yaml
# Verifica que la version de Node.js sea la misma
- name: Configurar Node.js
  uses: actions/setup-node@v4
  with:
    node-version: 20  # Usa la misma version que en local

Error: build falla por variables de entorno

plaintext
Error: NEXT_PUBLIC_SITE_URL is not defined

Causa: El build necesita variables de entorno que no estan configuradas en el workflow.

Solucion: Agrega las variables como secrets o variables en GitHub y pasalas en el step de build. Si necesitas una guia detallada, revisa variables de entorno en Next.js y Vercel.

Error: timeout en tests

plaintext
Error: Test timed out in 10000ms

Causa: Las maquinas de CI son mas lentas que tu maquina local. Un test que tarda 5 segundos local puede tardar 15 en CI.

Solucion: Aumenta el timeout en tu configuracion de Vitest:

typescript
// vitest.config.ts
export default defineConfig({
  test: {
    testTimeout: 30000, // 30 segundos
  },
})

Optimizaciones adicionales

Correr solo lo necesario

Si un push solo cambia archivos de documentacion, no tiene sentido correr el pipeline completo. Puedes filtrar por paths:

yaml
on:
  push:
    branches: [main]
    paths-ignore:
      - '*.md'
      - 'docs/**'
      - '.vscode/**'
  pull_request:
    branches: [main]
    paths-ignore:
      - '*.md'
      - 'docs/**'
      - '.vscode/**'

Notificaciones de fallos

GitHub envia emails por defecto cuando un workflow falla, pero puedes configurar notificaciones a Slack o Discord:

yaml
  notify:
    runs-on: ubuntu-latest
    needs: [build]
    if: failure()
    steps:
      - name: Notificar fallo en Discord
        uses: sarisia/actions-status-discord@v1
        with:
          webhook: ${{ secrets.DISCORD_WEBHOOK }}
          status: ${{ job.status }}
          title: "CI fallo"
          description: "El pipeline fallo en ${{ github.repository }}"

Badge de estado

Agrega un badge en tu README para mostrar el estado actual del pipeline:

markdown
![CI](https://github.com/TU-USUARIO/TU-REPO/actions/workflows/ci.yml/badge.svg)

Esto muestra un indicador verde (passing) o rojo (failing) en tiempo real.

Preguntas frecuentes

Cuantos minutos de GitHub Actions tengo disponibles?

PlanMinutos/mesAlmacenamiento
Free2,000500 MB
Pro3,0001 GB
Team3,0002 GB
Enterprise50,00050 GB

Los repositorios publicos tienen minutos ilimitados y gratuitos.

Puedo correr GitHub Actions solo en PRs, no en push a main?

Si. Cambia el trigger:

yaml
on:
  pull_request:
    branches: [main]

Esto es util si solo quieres validacion en PRs y confias en que el merge a main ya fue validado.

Como veo los logs de un run fallido?

Ve a tu repositorio > Actions > selecciona el run > haz clic en el job que fallo > expande el step con el error. GitHub muestra la salida completa de la terminal, incluyendo errores y stack traces.

El pipeline tarda mucho. Como lo optimizo?

Las tres optimizaciones con mayor impacto son:

  1. Cache de npm (cache: 'npm' en setup-node): Reduce instalacion de 60s a 5s
  2. Cache de Next.js (actions/cache para .next/cache): Reduce build de 60s a 20s
  3. Concurrency (cancelar runs anteriores): Evita runs duplicados

Puedo tener multiples workflows?

Si. Puedes crear archivos separados para diferentes propositos:

Estructura de archivos

.github/ └── workflows/ ├── ci.yml (lint, test, build en PRs) ├── deploy.yml (deploy a produccion en push a main) └── security.yml (auditoria semanal de dependencias)

Conclusion

El pipeline que construiste en esta guia cubre el 90% de lo que necesita un proyecto Next.js:

  1. Lint: Detecta errores de estilo y problemas obvios
  2. Test: Verifica que tu logica funcione correctamente
  3. Build: Confirma que TypeScript compila y el build de Next.js pasa
  4. Deploy: Lleva los cambios a produccion automaticamente

El archivo YAML completo tiene menos de 100 lineas. Lo configuras una vez y despues cada push y PR se valida automaticamente. Sin intervencion manual, sin olvidarte de correr los tests, sin deployear codigo roto.

Si ya tienes el deploy en Vercel configurado, solo necesitas la parte de CI. Si quieres control total del deploy, agrega el job final con la Vercel CLI. Y si tu plataforma de hosting es otra, el pipeline de CI sigue siendo exactamente el mismo.


Recursos adicionales

#github-actions#ci-cd#nextjs#devops#testing#deploy

Preguntas frecuentes

Que es CI/CD y por que lo necesito para mi proyecto Next.js?

CI/CD (Continuous Integration / Continuous Deployment) automatiza el proceso de probar y deployar tu codigo. Cada vez que haces push, automaticamente corre linting, tests y build. Si todo pasa, deploya a produccion. Elimina errores humanos y te da confianza en cada release.

GitHub Actions es gratis?

Si para repos publicos (ilimitado). Para repos privados, GitHub ofrece 2,000 minutos gratuitos al mes en el plan Free, y 3,000 en Pro. Para la mayoria de proyectos Next.js, esto es mas que suficiente.

Puedo usar GitHub Actions si mi hosting no es Vercel?

Si. GitHub Actions puede deployar a cualquier plataforma: Vercel, Netlify, Railway, DigitalOcean, AWS, o tu propio servidor. Solo necesitas cambiar el step de deployment.

Como manejo secrets como API keys en GitHub Actions?

GitHub tiene un sistema de Encrypted Secrets. Vas a Settings > Secrets and variables > Actions y agregas tus secrets ahi. En el workflow los accedes con la sintaxis secrets.TU_SECRET. Nunca se exponen en logs.

Cual es la diferencia entre CI y CD?

CI (Continuous Integration) se encarga de validar tu codigo: correr linter, tests y build automaticamente. CD (Continuous Deployment) va un paso mas alla y deploya automaticamente a produccion cuando CI pasa. Puedes tener solo CI o ambos.