Next.js: CI/CD com GitHub Actions

Última atualização: 2026-08-26

CI/CD é como "piloto automático" para equipes de desenvolvimento — cada commit passa automaticamente por um portão de qualidade, e apenas o código aprovado é implantado no ambiente de produção.

1. O Que Você Vai Aprender



2. Uma História Real de um Gerente Técnico

(1) Ponto Problemático: Implantação manual — ainda olhando para o terminal às 3 da manhã

Bob é o Líder Técnico da equipe TaskFlow, composta por cinco membros que mantêm uma plataforma SaaS com mais de 10.000 usuários. O processo de release toda sexta-feira é assim:

"Alice faz o merge do PR → Notifica Bob → Bob executa testes localmente → Clica manualmente em vercel deploy --prod após os testes passarem → Olha para o terminal por 10 minutos → Confirma que a implantação foi bem-sucedida → Envia uma mensagem para a equipe"

Na semana passada, Bob acidentalmente implantou uma versão desatualizada porque esqueceu de puxar o código mais recente antes do npm run build. Cinco minutos depois, os usuários não conseguiam fazer login, e levou mais 15 minutos para reverter as alterações. O atendimento ao cliente recebeu mais de 100 reclamações.

Pontos Problemáticos Impacto
Implantação Manual Alta taxa de erro humano (30% dos releases têm problemas)
Sem teste de controle de acesso automatizado Código com falhas ainda pode chegar à produção
Incompatibilidade de Ambiente Executa localmente, mas lança erro em produção
Sem PR Preview Não é possível ver os resultados antes do merge

(2) Solução com GitHub Actions

Bob projetou três linhas de montagem automatizadas:

YAML
# Cada vez que PR → Lint + test + build automáticos
# Merge na main → Build Automatizado + Deploy no Vercel
# Todo dia de madrugada → Build Automatizado da Imagem Docker

(3) Resultados

Dimensão Implantação Manual Automação CI/CD
Tempo para publicar 30 minutos 8 minutos
Erro humano 30% < 1%
Eficiência na Revisão de PR Apenas Código Código + URL de Preview
Frequência de Implantação Uma vez por semana 5 vezes por dia


3. Fundamentos do GitHub Actions

Actions é a plataforma CI/CD integrada do GitHub que usa arquivos YAML para definir workflows.

100%
graph LR
    A[git push] --> B[GitHub Actions]
    B --> C[Eventos Gatilho]
    C --> D[Jobs Paralelos/Seriados]
    D --> E[Steps Etapas]
    E --> F[Componentes do Actions Market]
    
    style B fill:#cce5ff
    style D fill:#d4edda
Conceito Descrição Exemplo
Workflow Um arquivo YAML = Um processo de automação .github/workflows/test.yml
Event Evento que aciona o workflow push, pull_request, schedule
Job Um conjunto de etapas (que podem ser paralelas ou dependentes) linttestdeploy
Step Um único comando ou Action npm run lint, actions/checkout
Runner Ambiente de Execução ubuntu-latest, windows-latest

(1) Estrutura do Arquivo de Workflow

YAML
# .github/workflows/ci.yml
name: Pipeline CI

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

env:
  NODE_VERSION: '20'
  TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}

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

  test:
    needs: [lint]
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: ['18', '20', '22']
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
      - run: npm ci
      - run: npm test
      - run: npm run test:coverage
      - uses: codecov/codecov-action@v4
        with:
          token: ${{ secrets.CODECOV_TOKEN }}

  build:
    needs: [test]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
      - run: npm ci
      - run: npm run build
      - uses: actions/upload-artifact@v4
        with:
          name: build-output
          path: .next/


4. test.yml: Testes em Matriz Paralela

100%
graph TB
    A[Git Push / PR] --> B[lint]
    B --> C[test 18.x]
    B --> D[test 20.x]
    B --> E[test 22.x]
    C --> F[build]
    D --> F
    E --> F
    F --> G[Upload de Artefatos de Build]
    
    style A fill:#cce5ff
    style C fill:#d4edda
    style D fill:#d4edda
    style E fill:#d4edda

(1) test.yml Completo

YAML
# .github/workflows/test.yml
name: Suíte de Testes

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

jobs:
  lint:
    name: Verificação Lint
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - uses: actions/checkout@v4
      
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
          
      - name: Instalar dependências
        run: npm ci
          
      - name: Verificação de tipo TypeScript
        run: npx tsc --noEmit
        
      - name: Verificação ESLint
        run: npm run lint
        
      - name: Verificação Prettier
        run: npx prettier --check "src/**/*.{ts,tsx}"

  unit-and-integration:
    name: Testes Unitários e de Integração
    needs: [lint]
    runs-on: ubuntu-latest
    timeout-minutes: 15
    
    strategy:
      matrix:
        node-version: ['18', '20', '22']
      fail-fast: false
    
    services:
      postgres:
        image: postgres:16-alpine
        env:
          POSTGRES_USER: test
          POSTGRES_PASSWORD: test
          POSTGRES_DB: testdb
        ports:
          - 5432:5432
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
    
    steps:
      - uses: actions/checkout@v4
      
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: 'npm'
          
      - name: Instalar dependências
        run: npm ci
          
      - name: Gerar cliente Prisma
        run: npx prisma generate
          
      - name: Executar migrações do banco de dados
        run: npx prisma migrate deploy
        env:
          DATABASE_URL: postgresql://test:test@localhost:5432/testdb
          
      - name: Executar testes unitários
        run: npm run test
        env:
          DATABASE_URL: postgresql://test:test@localhost:5432/testdb
          
      - name: Executar testes de integração
        run: npm run test:integration
        env:
          DATABASE_URL: postgresql://test:test@localhost:5432/testdb
          
      - name: Fazer upload da cobertura
        uses: codecov/codecov-action@v4
        with:
          token: ${{ secrets.CODECOV_TOKEN }}
          flags: unittests
          name: codecov-node-${{ matrix.node-version }}

  e2e:
    name: Testes E2E
    needs: [lint]
    runs-on: ubuntu-latest
    timeout-minutes: 20
    
    steps:
      - uses: actions/checkout@v4
      
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
          
      - name: Instalar dependências
        run: npm ci
          
      - name: Instalar navegadores Playwright
        run: npx playwright install --with-deps chromium
        
      - name: Executar testes E2E
        run: npx playwright test --project=chromium
        env:
          TEST_DATABASE_URL: ${{ secrets.TEST_DATABASE_URL }}
          
      - uses: actions/upload-artifact@v4
        if: failure()
        with:
          name: playwright-report
          path: playwright-report/
          retention-days: 7

  build:
    name: Verificação de Build
    needs: [unit-and-integration]
    runs-on: ubuntu-latest
    timeout-minutes: 10
    
    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-artifact@v4
        with:
          name: next-build
          path: .next/
          retention-days: 1

▶ Exemplo: Resultados do Teste em Matriz Paralela

TEXT 📖 Somente leitura
# Saída do Console do GitHub Actions
Job: unit-and-integration (node-version: 18.x)  ✓ 3m 12s
Job: unit-and-integration (node-version: 20.x)  ✓ 2m 58s
Job: unit-and-integration (node-version: 22.x)  ✓ 3m 05s

Resumo:
  ✓ lint                        (1 job)  0m 45s
  ✓ unit-and-integration        (3 jobs) 3m 12s
  ✓ e2e                         (1 job)  4m 30s
  ✓ build                       (1 job)  1m 20s


5. deploy.yml: Implantação automática no Vercel

Ambiente de Implantação Condições de Gatilho Destino
Preview Criar/Atualizar PR Implantar no Branch de Preview
Produção Merge na main Atualização do ambiente de produção
Staging Tag de release Validação pré-release

(1) Configuração de Deploy no Vercel

YAML
# .github/workflows/deploy.yml
name: Implantar no Vercel

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

env:
  VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
  VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}

jobs:
  deploy-preview:
    name: Implantar Preview
    if: github.event_name == 'pull_request'
    runs-on: ubuntu-latest
    timeout-minutes: 15
    
    steps:
      - uses: actions/checkout@v4
      
      - name: Instalar Vercel CLI
        run: npm install --global vercel@latest
      
      - name: Puxar Ambiente Vercel
        run: vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }}
        
      - name: Construir Artefatos do Projeto
        run: vercel build --token=${{ secrets.VERCEL_TOKEN }}
        
      - name: Implantar no Vercel Preview
        run: |
          vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }} > deployment-url.txt
          echo "PREVIEW_URL=$(cat deployment-url.txt)" >> $GITHUB_ENV
      
      - name: Comentar URL de Preview no PR
        uses: thollander/actions-comment-pull-request@v2
        with:
          message: |
            🚀 **Implantação de Preview Pronta**
            
            | Ambiente | URL |
            |:-----------|:----|
            | Preview | ${{ env.PREVIEW_URL }} |
            | Branch | ${{ github.head_ref }} |
            
            _Este comentário é atualizado automaticamente a cada push._

  deploy-production:
    name: Implantar Produção
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    needs: [deploy-preview]
    runs-on: ubuntu-latest
    timeout-minutes: 15
    environment: production
    
    steps:
      - uses: actions/checkout@v4
      
      - name: Instalar Vercel CLI
        run: npm install --global vercel@latest
      
      - name: Puxar Ambiente Vercel
        run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }}
        
      - name: Construir Artefatos do Projeto
        run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }}
        
      - name: Implantar no Vercel Produção
        run: vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }}
      
      - name: Notificar sucesso da implantação
        uses: slackapi/slack-github-action@v1
        with:
          payload: |
            {
              "text": "✅ Implantação em produção concluída: ${{ github.repository }}@${{ github.sha }}"
            }
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}


6. Build de Imagem Docker (Multi-estágio, 358 MB)

Para implantações self-hosted, você precisa construir automaticamente imagens Docker no CI.

(1) Dockerfile Multi-estágio

DOCKERFILE
# Dockerfile — Build de imagem standalone Next.js 16
# Fase 1: Instalação de Dependências (Usando Camada de Cache)
FROM node:20-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --only=production && \
    npm cache clean --force

# Fase 2: Build (Gerar artefatos .next)
FROM node:20-alpine AS build
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
ENV NEXT_TELEMETRY_DISABLED=1
RUN npm run build

# Fase 3: Execução (Imagem minimizada ~358MB)
FROM node:20-alpine AS runner
WORKDIR /app

ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1

RUN addgroup --system --gid 1001 nodejs && \
    adduser --system --uid 1001 nextjs

COPY --from=build /app/public ./public
COPY --from=build --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=build --chown=nextjs:nodejs /app/.next/static ./.next/static

USER nextjs

EXPOSE 3000

ENV PORT=3000
ENV HOSTNAME="0.0.0.0"

CMD ["node", "server.js"]

(2) Action de Build Docker

YAML
# .github/workflows/docker.yml
name: Docker Build & Push

on:
  push:
    tags: ['v*']
  schedule:
    - cron: '0 2 * * 0'  # Domingo de madrugada às 2h

jobs:
  docker:
    runs-on: ubuntu-latest
    timeout-minutes: 30
    
    steps:
      - uses: actions/checkout@v4
      
      - name: Configurar QEMU
        uses: docker/setup-qemu-action@v3
      
      - name: Configurar Docker Buildx
        uses: docker/setup-buildx-action@v3
      
      - name: Fazer login no GitHub Container Registry
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      
      - name: Docker meta
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ghcr.io/${{ github.repository }}
          tags: |
            type=semver,pattern={{version}}
            type=semver,pattern={{major}}.{{minor}}
            type=sha,format=short
            type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
      
      - name: Build e push
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

▶ Exemplo: Saída do build da imagem Docker

TEXT 📖 Somente leitura
# Log de Build
#1 [deps 1/1] RUN npm ci --only=production
#1 DONE 15.2s

#2 [build 1/4] COPY --from=deps /app/node_modules ./node_modules
#2 DONE 0.1s

#3 [build 2/4] COPY . .
#3 DONE 0.3s

#4 [build 3/4] RUN npm run build
#4 DONE 28.5s

#5 [runner 1/6] COPY --from=build /app/public ./public
#5 DONE 0.1s

#6 Exportando camadas
#6 DONE 3.2s

# Análise do Tamanho da Imagem
ghcr.io/myorg/taskflow:latest   358 MB


7. Variáveis de Ambiente e Gerenciamento de Secrets

100%
graph TB
    A[GitHub Secrets] --> B[Ambiente de Execução Actions]
    B --> C[Vercel Token]
    B --> D[URL do Banco de Dados]
    B --> E[Chaves de API]
    B --> F[Slack Webhook]
    C --> G[Implantar no Vercel]
    D --> H[Executar Teste]
    E --> I[Injeção Durante a Construção]
    F --> J[Aviso de Implantação]
    
    style A fill:#cce5ff
    style B fill:#d4edda
Nome da Variável de Ambiente Propósito Origem
VERCEL_TOKEN Autenticação da API Vercel GitHub Secrets
VERCEL_ORG_ID ID da Equipe Vercel Painel Vercel
VERCEL_PROJECT_ID ID do Projeto Vercel Painel Vercel
DATABASE_URL Conexão com Banco de Dados GitHub Secrets
CODECOV_TOKEN Upload de Cobertura Site Codecov
SLACK_WEBHOOK_URL Aviso de Implantação Configuração do App Slack

(1) Configurar GitHub Secrets

BASH
# Em GitHub Repository → Settings → Secrets and variables → Actions → Add

gh secret set VERCEL_TOKEN --body "seu-vercel-token"
gh secret set DATABASE_URL --body "postgresql://user:pass@host:5432/db"
gh secret set SLACK_WEBHOOK_URL --body "https://hooks.slack.com/services/..."

(2) Estratégia de Isolamento de Ambiente

YAML
# Sobrescrita de Variáveis em Diferentes Ambientes
jobs:
  test:
    env:
      DATABASE_URL: postgresql://test:test@localhost:5432/testdb
      NODE_ENV: test
      
  deploy-preview:
    environment: preview
    env:
      DATABASE_URL: ${{ secrets.PREVIEW_DATABASE_URL }}
      NEXT_PUBLIC_API_URL: ${{ vars.PREVIEW_API_URL }}
      
  deploy-production:
    environment: production
    env:
      DATABASE_URL: ${{ secrets.PROD_DATABASE_URL }}
      NEXT_PUBLIC_API_URL: https://api.taskflow.io


8. Workflow de Implantação de PR Preview

PR Preview permite que desenvolvedores visualizem os efeitos de suas alterações antes do merge.

100%
graph TB
    A[Desenvolvedor Cria PR] --> B[Actions Aciona deploy-preview]
    B --> C[Vercel Cria Implantação de Preview]
    C --> D[Gerar URL de preview]
    D --> E[Bot Comenta no PR Adiciona um link]
    E --> F[O revisor faz Upload de Preview para verificação]
    F -->|Aprovação| G[Merge na main]
    G --> H[Actions Aciona deploy-production]
    
    style A fill:#cce5ff
    style F fill:#fff3cd
    style H fill:#d4edda

▶ Exemplo: Workflow Completo de PR Preview + Limpeza

Saída:

TEXT 📖 Somente leitura
Salve a configuração YAML acima no caminho de arquivo especificado. As configurações entrarão em vigor na próxima reinicialização do servidor.
YAML
# .github/workflows/preview.yml
name: PR Preview

on:
  pull_request:
    types: [opened, synchronize, closed]

jobs:
  preview:
    if: github.event.action != 'closed'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Implantar no Vercel Preview
        id: deploy
        run: |
          npx vercel --token=${{ secrets.VERCEL_TOKEN }} \
            --scope=${{ secrets.VERCEL_ORG_ID }} \
            --confirm > preview-url.txt
          echo "url=$(cat preview-url.txt)" >> $GITHUB_OUTPUT
      
      - name: Comentar URL
        uses: actions/github-script@v7
        with:
          script: |
            const url = '${{ steps.deploy.outputs.url }}'
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: `🚀 **Preview implantado**\n\n${url}\n\n_Commit: ${context.sha}_`
            })

  cleanup:
    if: github.event.action == 'closed'
    runs-on: ubuntu-latest
    steps:
      - name: Remover Vercel Preview
        run: |
          npx vercel remove \
            taskflow-git-${GITHUB_HEAD_REF//\//-} \
            --token=${{ secrets.VERCEL_TOKEN }} \
            --yes --scope=${{ secrets.VERCEL_ORG_ID }} || true

Saída:

TEXT 📖 Somente leitura
Seções: name, on, jobs.


9. Exemplo Completo: Pipeline CI/CD Completo do TaskFlow

YAML
# .github/workflows/full-pipeline.yml
# ============================================
# Linha de Montagem CI/CD Completa do TaskFlow
# ============================================
name: Pipeline Completo TaskFlow

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]
  release:
    types: [published]

env:
  NODE_VERSION: '20'
  PNPM_VERSION: '9'

jobs:
  # === Fase 1: Controle de Acesso de Qualidade ===
  quality-gate:
    name: Portão de Qualidade
    runs-on: ubuntu-latest
    timeout-minutes: 10
    
    steps:
      - uses: actions/checkout@v4
      
      - uses: pnpm/action-setup@v4
        with:
          version: ${{ env.PNPM_VERSION }}
      
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'pnpm'
      
      - run: pnpm install --frozen-lockfile
      
      - name: Verificação TypeScript
        run: pnpm typecheck
        
      - name: ESLint + Prettier
        run: pnpm lint && pnpm format:check
        
      - name: Testes unitários com cobertura
        run: pnpm test:coverage
        
      - name: Upload de cobertura
        uses: codecov/codecov-action@v4
        with:
          token: ${{ secrets.CODECOV_TOKEN }}
          fail_ci_if_error: false

  # === Fase 2: Testes de Integração ===
  integration:
    name: Testes de Integração
    needs: [quality-gate]
    runs-on: ubuntu-latest
    timeout-minutes: 20
    
    services:
      postgres:
        image: postgres:16-alpine
        env:
          POSTGRES_USER: taskflow
          POSTGRES_PASSWORD: taskflow
          POSTGRES_DB: taskflow_test
        ports:
          - 5432:5432
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
    
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v4
        with:
          version: ${{ env.PNPM_VERSION }}
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'pnpm'
      
      - run: pnpm install --frozen-lockfile
      - run: npx prisma generate
      - run: npx prisma migrate deploy
        env:
          DATABASE_URL: postgresql://taskflow:taskflow@localhost:5432/taskflow_test
      
      - name: Testes de integração
        run: pnpm test:integration
        env:
          DATABASE_URL: postgresql://taskflow:taskflow@localhost:5432/taskflow_test
      
      - name: Testes E2E
        run: npx playwright install --with-deps chromium && pnpm test:e2e
        env:
          DATABASE_URL: postgresql://taskflow:taskflow@localhost:5432/taskflow_test

  # === Fase 3: Build ===
  build:
    name: Construir Aplicação
    needs: [integration]
    runs-on: ubuntu-latest
    timeout-minutes: 15
    outputs:
      image-tag: ${{ steps.meta.outputs.tags }}
    
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v4
        with:
          version: ${{ env.PNPM_VERSION }}
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'pnpm'
      
      - run: pnpm install --frozen-lockfile
      - run: pnpm build
      
      - name: Construir imagem Docker
        if: github.event_name == 'push'
        uses: docker/build-push-action@v5
        with:
          context: .
          load: true
          tags: taskflow:ci-${{ github.sha }}
      
      - name: Salvar saídas de build
        uses: actions/upload-artifact@v4
        with:
          name: build-artifacts
          path: |
            .next/
            public/
            package.json

  # === Fase 4: Implantação ===
  deploy:
    name: Implantar
    needs: [build]
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    environment: production
    timeout-minutes: 15
    
    steps:
      - uses: actions/checkout@v4
      
      - name: Implantar no Vercel
        run: |
          npx vercel deploy --prod \
            --token=${{ secrets.VERCEL_TOKEN }} \
            --scope=${{ secrets.VERCEL_ORG_ID }}
      
      - name: Notificar Slack
        uses: slackapi/slack-github-action@v1
        with:
          payload: |
            {
              "text": "✅ TaskFlow implantado em produção\nCommit: ${{ github.sha }}\nPor: ${{ github.actor }}"
            }
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
      
      - name: Executar Lighthouse CI
        run: npx lhci autorun
        env:
          LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_TOKEN }}

❓ Perguntas Frequentes

P: A cota gratuita do GitHub Actions é suficiente? R: O plano GitHub Free oferece 2.000 minutos por mês de tempo de execução do Actions (ilimitado para repositórios públicos). Um pipeline CI típico do Next.js leva cerca de 8–12 minutos por execução, então 2.000 minutos podem suportar aproximadamente 200 execuções por mês. Se precisar de mais, o GitHub Team oferece 3.000 minutos por mês, ou você pode configurar e auto-hospedar seus próprios runners.

P: Por que é necessário realizar testes em matriz em várias versões do Node.js? R: Seus usuários podem estar executando sua aplicação em várias versões do Node (Vercel usa 18.x, enquanto Docker pode usar 20.x ou 22.x). Testes em matriz garantem que seu código funcione corretamente em todas as versões suportadas do Node. O Next.js 16 suporta oficialmente Node 18.17 e posteriores; testar as três versões LTS mais recentes é a melhor prática.

P: Qual é melhor, vercel-action ou a Vercel CLI? R: vercel-action (amondnet/vercel-action) encapsula operações comuns da CLI, mas as atualizações podem ser atrasadas. Recomendamos usar a Vercel CLI (npm install -g vercel) diretamente; usar run: vercel deploy --prod --token=... no Actions oferece maior flexibilidade e garante que você tenha a versão mais recente.

P: Como posso proteger secrets contra vazamento? R: (1) Use GitHub Encrypted Secrets em vez de armazená-los em texto plano no YAML; (2) Desabilite a injeção automática de secrets para pull requests de forks (Settings → Actions → Fork pull request workflows); (3) Rotacione secrets regularmente; (4) Use actions/secrets-scanning para detectar commits acidentais.

P: Qual é a diferença entre PR Preview e o Preview padrão do Vercel? R: O Vercel cria automaticamente uma Implantação de Preview para cada PR (integrado com Git), mas você precisa fazer login no Painel Vercel para ver a URL. Ao implantar manualmente via GitHub Actions e comentar a URL no PR, os membros da equipe podem clicar para acessar diretamente da página do PR, o que proporciona uma experiência melhor.

P: Como posso otimizar um pipeline CI lento? R: (1) Use actions/cache para fazer cache de node_modules e .next/cache; (2) Execute jobs independentes em paralelo; (3) Use fail-fast: false para evitar que uma falha em uma única versão cause o cancelamento de todo o pipeline; (4) Use pnpm em vez de npm (para instalação mais rápida); (5) Auto-hospede um runner (se o repositório for grande).


📖 Resumo


📝 Exercícios

  1. Problema Básico (⭐): Crie um .github/workflows/ci.yml que contenha três jobs seriais — Lint, Test e Build — e acione-o sempre que push fizer a transição para main.

  2. Exercício Avançado (⭐⭐): Configure um pipeline completo de implantação automatizada no Vercel para seu projeto: (1) Configure VERCEL_TOKEN no GitHub Secrets; (2) Escreva deploy.yml para implementar PR Preview e implantação em produção; (3) Verifique se a URL de Preview aparece nos comentários do PR.

  3. Desafio (⭐⭐⭐): Implemente um pipeline CI/CD multi-ambiente (dev → staging → production): (1) Cada ambiente tem seu próprio banco de dados e secrets; (2) O branch dev é automaticamente implantado no ambiente dev; (3) O branch main é automaticamente implantado no staging; (4) A implantação em produção requer aprovação manual; (5) Notifique um canal Slack via webhook após uma implantação bem-sucedida.

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%