DevToolBoxGRATIS
Blog

GitHub Actions CI/CD: Tutorial completo para desarrolladores

15 minpor DevToolBox

What Are GitHub Actions?

GitHub Actions is a CI/CD and workflow automation platform built directly into GitHub. It allows you to automate building, testing, and deploying your code whenever events occur in your repository -- such as pushes, pull requests, issue creation, or scheduled triggers. Since its launch, GitHub Actions has become one of the most popular CI/CD solutions due to its tight integration with GitHub and generous free tier.

This tutorial covers everything from writing your first workflow to advanced patterns including matrix builds, reusable workflows, self-hosted runners, caching, secrets management, and deployment strategies. By the end, you will be able to set up production-grade CI/CD pipelines for any project.

Core Concepts

GitHub Actions Hierarchy:

  Workflow (.yml file)
    └── Job (runs on a runner)
        └── Step (individual task)
            └── Action (reusable unit)

Key Terms:
  Workflow   - Automated process defined in YAML
  Event      - Trigger that starts a workflow (push, PR, schedule)
  Job        - Set of steps that run on the same runner
  Step       - Individual task (run command or use action)
  Action     - Reusable unit of code (from Marketplace or custom)
  Runner     - Server that executes jobs (GitHub-hosted or self-hosted)
  Artifact   - Files produced by a workflow (build output, logs)
  Secret     - Encrypted environment variable

Your First Workflow

Workflows are defined as YAML files in the .github/workflows/ directory of your repository. Here is a complete CI workflow for a Node.js project that runs tests on every push and pull request.

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

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

# Cancel in-progress runs for the same ref
concurrency:
  group: ci-${github.ref}
  cancel-in-progress: true

jobs:
  test:
    name: Test
    runs-on: ubuntu-latest

    steps:
      # 1. Check out code
      - name: Checkout repository
        uses: actions/checkout@v4

      # 2. Set up Node.js
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      # 3. Install dependencies
      - name: Install dependencies
        run: npm ci

      # 4. Run linter
      - name: Lint
        run: npm run lint

      # 5. Run tests
      - name: Run tests
        run: npm test

      # 6. Build
      - name: Build
        run: npm run build

Workflow Triggers (Events)

GitHub Actions supports dozens of event triggers. Understanding when and how workflows run is essential for efficient CI/CD pipelines.

# Common triggers

# Push to specific branches
on:
  push:
    branches: [main, 'release/**']
    paths:
      - 'src/**'          # Only run when source code changes
      - '!docs/**'        # Ignore docs changes
    tags:
      - 'v*'              # Run on version tags

# Pull request events
on:
  pull_request:
    types: [opened, synchronize, reopened]
    branches: [main]

# Scheduled (cron)
on:
  schedule:
    - cron: '0 6 * * 1'   # Every Monday at 6:00 UTC

# Manual trigger with inputs
on:
  workflow_dispatch:
    inputs:
      environment:
        description: 'Deploy environment'
        required: true
        default: 'staging'
        type: choice
        options:
          - staging
          - production
      dry_run:
        description: 'Dry run (no actual deploy)'
        type: boolean
        default: false

# Multiple triggers
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
  workflow_dispatch:    # Also allow manual runs

Matrix Builds

Matrix strategies let you run the same job across multiple configurations -- different operating systems, language versions, or any custom parameter. This is essential for testing cross-platform compatibility.

jobs:
  test:
    name: Test (${matrix.os}, Node ${matrix.node-version})
    runs-on: ${matrix.os}

    strategy:
      fail-fast: false    # Don't cancel other jobs if one fails
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
        node-version: [18, 20, 22]
        exclude:
          - os: windows-latest
            node-version: 18     # Skip Node 18 on Windows
        include:
          - os: ubuntu-latest
            node-version: 22
            experimental: true   # Extra variable for this combo

    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${matrix.node-version}
      - run: npm ci
      - run: npm test
        continue-on-error: ${matrix.experimental == true}

Caching and Performance

Caching dependencies significantly speeds up workflow execution. GitHub provides built-in caching actions that work across workflow runs.

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      # Node.js with built-in caching
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'           # Auto-caches ~/.npm

      # Custom cache for build output
      - name: Cache Next.js build
        uses: actions/cache@v4
        with:
          path: |
            .next/cache
            node_modules/.cache
          key: nextjs-${runner.os}-${hashFiles('package-lock.json')}-${hashFiles('src/**')}
          restore-keys: |
            nextjs-${runner.os}-${hashFiles('package-lock.json')}-
            nextjs-${runner.os}-

      - run: npm ci
      - run: npm run build

      # Upload build artifacts
      - name: Upload build artifacts
        uses: actions/upload-artifact@v4
        with:
          name: build-output
          path: .next/
          retention-days: 7

Secrets and Environment Variables

GitHub Actions provides encrypted secrets for sensitive data like API keys, tokens, and passwords. Secrets are never exposed in logs and can be scoped to repositories, environments, or organizations.

jobs:
  deploy:
    runs-on: ubuntu-latest

    # Environment with protection rules
    environment:
      name: production
      url: https://example.com

    # Environment variables
    env:
      NODE_ENV: production
      API_BASE_URL: https://api.example.com

    steps:
      - uses: actions/checkout@v4

      # Access secrets
      - name: Deploy
        env:
          AWS_ACCESS_KEY_ID: ${secrets.AWS_ACCESS_KEY_ID}
          AWS_SECRET_ACCESS_KEY: ${secrets.AWS_SECRET_ACCESS_KEY}
          DEPLOY_TOKEN: ${secrets.DEPLOY_TOKEN}
        run: |
          echo "Deploying to production..."
          # Secrets are automatically masked in logs
          aws s3 sync ./dist s3://my-bucket

      # Using GITHUB_TOKEN (automatically provided)
      - name: Create Release
        uses: actions/create-release@v1
        env:
          GITHUB_TOKEN: ${secrets.GITHUB_TOKEN}
        with:
          tag_name: ${github.ref_name}
          release_name: Release ${github.ref_name}

Reusable Workflows

Reusable workflows let you define a workflow once and call it from other workflows. This eliminates duplication across repositories and ensures consistent CI/CD practices.

# .github/workflows/reusable-deploy.yml (called workflow)
name: Reusable Deploy

on:
  workflow_call:
    inputs:
      environment:
        required: true
        type: string
      node-version:
        required: false
        type: string
        default: '20'
    secrets:
      deploy-token:
        required: true

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: ${inputs.environment}
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${inputs.node-version}
      - run: npm ci && npm run build
      - name: Deploy
        env:
          TOKEN: ${secrets.deploy-token}
        run: ./deploy.sh ${inputs.environment}
# .github/workflows/production.yml (caller workflow)
name: Production Deploy

on:
  push:
    tags: ['v*']

jobs:
  deploy:
    uses: ./.github/workflows/reusable-deploy.yml
    with:
      environment: production
    secrets:
      deploy-token: ${secrets.DEPLOY_TOKEN}

Common CI/CD Patterns

# Pattern: Test -> Build -> Deploy pipeline
name: Full Pipeline

on:
  push:
    branches: [main]

jobs:
  test:
    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 test -- --coverage
      - name: Upload coverage
        uses: actions/upload-artifact@v4
        with:
          name: coverage
          path: coverage/

  build:
    needs: test           # Depends on test job
    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-artifact@v4
        with:
          name: dist
          path: dist/

  deploy-staging:
    needs: build          # Depends on build job
    runs-on: ubuntu-latest
    environment: staging
    steps:
      - uses: actions/download-artifact@v4
        with: { name: dist }
      - run: echo "Deploy to staging..."

  deploy-production:
    needs: deploy-staging  # Depends on staging deploy
    runs-on: ubuntu-latest
    environment: production
    if: github.ref == 'refs/heads/main'
    steps:
      - uses: actions/download-artifact@v4
        with: { name: dist }
      - run: echo "Deploy to production..."

Docker and Container Workflows

name: Docker Build & Push

on:
  push:
    branches: [main]
    tags: ['v*']

jobs:
  docker:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write

    steps:
      - uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Login to GitHub Container Registry
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${github.actor}
          password: ${secrets.GITHUB_TOKEN}

      - name: Extract metadata
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ghcr.io/${github.repository}
          tags: |
            type=sha
            type=ref,event=branch
            type=semver,pattern={{version}}

      - name: Build and push
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ${steps.meta.outputs.tags}
          cache-from: type=gha
          cache-to: type=gha,mode=max

Debugging Workflows

# Enable debug logging
# Set repository secret: ACTIONS_RUNNER_DEBUG = true

steps:
  # Print useful context information
  - name: Debug info
    run: |
      echo "Event: $GITHUB_EVENT_NAME"
      echo "Ref: $GITHUB_REF"
      echo "SHA: $GITHUB_SHA"
      echo "Actor: $GITHUB_ACTOR"
      echo "Runner OS: $RUNNER_OS"

  # Conditional step for debugging
  - name: Debug on failure
    if: failure()
    run: |
      echo "Previous step failed!"
      cat logs/error.log || true

  # SSH into runner for debugging (tmate)
  - name: Setup tmate session
    if: failure()
    uses: mxschmitt/action-tmate@v3
    timeout-minutes: 15

Best Practices

GitHub Actions Best Practices:

Security:
  - Never hardcode secrets in workflow files
  - Pin actions to full commit SHA, not just version tags
  - Use environment protection rules for production deploys
  - Limit GITHUB_TOKEN permissions with 'permissions' key
  - Audit third-party actions before using them

Performance:
  - Use caching for dependencies and build artifacts
  - Enable concurrency groups to cancel stale runs
  - Use matrix strategies wisely (avoid unnecessary combos)
  - Prefer npm ci over npm install
  - Use path filters to skip irrelevant workflows

Maintainability:
  - Use reusable workflows to eliminate duplication
  - Keep workflows focused (separate CI, deploy, release)
  - Use meaningful job and step names
  - Document complex workflows with comments
  - Store common configurations in composite actions

Cost Management:
  - Cancel redundant workflow runs with concurrency groups
  - Use path filters to avoid running on non-code changes
  - Cache aggressively to reduce build times
  - Use self-hosted runners for heavy workloads

Frequently Asked Questions

Is GitHub Actions free?

GitHub Actions is free for public repositories with unlimited minutes. For private repositories, the free tier includes 2,000 minutes per month for GitHub Free accounts and 3,000 minutes for Pro accounts. Linux runners consume 1x minutes, Windows runners 2x, and macOS runners 10x. Self-hosted runners do not count against your quota.

How do I run workflows only when specific files change?

Use the paths filter in your trigger configuration. For example, paths: ['src/**', 'package.json'] will only trigger the workflow when files in the src/ directory or package.json change. You can also use paths-ignore to exclude specific paths like documentation files.

Can I run GitHub Actions locally?

Yes. The act tool (github.com/nektos/act) lets you run GitHub Actions locally using Docker. It supports most workflow features and is invaluable for debugging. Install it with brew install act on macOS or download the binary for your platform.

How do I pass data between jobs?

Use artifacts (actions/upload-artifact and actions/download-artifact) to pass files between jobs. For small values, use job outputs: set an output in one job with echo "key=value" >> $GITHUB_OUTPUT and reference it in dependent jobs with needs.job_name.outputs.key.

Related Tools and Guides

𝕏 Twitterin LinkedIn
¿Fue útil?

Mantente actualizado

Recibe consejos de desarrollo y nuevas herramientas.

Sin spam. Cancela cuando quieras.

Prueba estas herramientas relacionadas

{ }JSON FormatterYMLYAML Validator & FormatterY{}JSON ↔ YAML Converter🐳Docker Compose Generator

Artículos relacionados

Validación YAML Docker Compose: 10 errores de sintaxis comunes y cómo corregirlos

Deja de perder tiempo con errores YAML de Docker Compose. Aprende a identificar y corregir los 10 errores más comunes.

Estrategias de ramificacion Git: GitFlow vs Trunk-Based vs GitHub Flow

Compara las estrategias GitFlow, Trunk-Based Development y GitHub Flow. Estructuras de ramas, flujos de merge, integracion CI/CD y como elegir la estrategia correcta.

Cron para Serverless: GitHub Actions, Vercel Cron y Cloudflare Workers

Domina las expresiones cron en plataformas serverless. Sintaxis, errores de zona horaria y ejemplos.

Mejores prácticas de Dockerfile y builds multi-etapa

Escribe Dockerfiles optimizados con builds multi-etapa, caché de capas y seguridad. Ejemplos para Node.js, Python y Go.