cicd

GitHub Actions Tutorial: Complete CI/CD Guide for Beginners (2025)

Master GitHub Actions from scratch. Learn to build, test, and deploy applications automatically with this comprehensive tutorial including real-world examples.

CE

CloudElevate Team

DevOps Engineers

📝cicd

GitHub Actions is the most popular CI/CD platform for modern development teams. It's built directly into GitHub, completely free for public repositories, and offers generous free minutes for private repos. In this tutorial, you'll learn everything from basic workflows to advanced deployment patterns.

What is GitHub Actions?

GitHub Actions is a CI/CD platform that automates your software development workflows. Every time you push code, open a PR, or trigger an event, GitHub Actions can automatically:

  • Build and compile your code
  • Run tests (unit, integration, e2e)
  • Check code quality and security
  • Deploy to any cloud provider
  • Send notifications and update status

Key Concepts

Workflows

A workflow is an automated process defined in a YAML file. Workflows live in the .github/workflows/ directory of your repository.

Jobs

A workflow contains one or more jobs that run in parallel by default. Each job runs on a fresh virtual machine (runner).

Steps

Jobs contain steps that execute commands or actions. Steps run sequentially within a job.

Actions

Actions are reusable units of code. You can use actions from the GitHub Marketplace or create your own.

Your First GitHub Actions Workflow

Let's create a simple workflow that runs on every push. Create this file at .github/workflows/ci.yml:

ci.yml
name: CI Pipeline

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

jobs:
  build:
    runs-on: ubuntu-latest
    
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
      
      - name: Install dependencies
        run: npm ci
      
      - name: Run linter
        run: npm run lint
      
      - name: Run tests
        run: npm test
      
      - name: Build
        run: npm run build

Workflow Triggers (Events)

GitHub Actions supports many trigger events:

triggers.yml
# Push to specific branches
on:
  push:
    branches: [main, 'release/*']
    
# Pull requests
on:
  pull_request:
    types: [opened, synchronize, reopened]

# Scheduled (cron)
on:
  schedule:
    - cron: '0 0 * * *'  # Daily at midnight

# Manual trigger
on:
  workflow_dispatch:
    inputs:
      environment:
        description: 'Deployment environment'
        required: true
        default: 'staging'

# On release
on:
  release:
    types: [published]

Matrix Builds: Test Multiple Configurations

Test your code across multiple Node versions and operating systems:

matrix.yml
jobs:
  test:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
        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

Using Secrets and Environment Variables

Store sensitive data like API keys in GitHub Secrets:

secrets.yml
jobs:
  deploy:
    runs-on: ubuntu-latest
    env:
      NODE_ENV: production
    
    steps:
      - uses: actions/checkout@v4
      
      - name: Deploy to AWS
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        run: |
          aws s3 sync ./dist s3://my-bucket

Artifacts and Caching

Saving Build Artifacts

Share files between jobs or download them later:

artifacts.yml
- name: Build
  run: npm run build

- name: Upload artifact
  uses: actions/upload-artifact@v4
  with:
    name: build-output
    path: dist/
    retention-days: 7

Caching Dependencies

Speed up workflows by caching npm packages:

cache.yml
- uses: actions/setup-node@v4
  with:
    node-version: '20'
    cache: 'npm'  # Built-in caching!

# Or manual caching
- name: Cache node modules
  uses: actions/cache@v4
  with:
    path: ~/.npm
    key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}

Real-World Deployment Examples

Deploy to AWS S3 + CloudFront

deploy-aws.yml
name: Deploy to AWS

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
      
      - name: Install and Build
        run: |
          npm ci
          npm run build
      
      - name: Configure AWS
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: us-east-1
      
      - name: Deploy to S3
        run: aws s3 sync ./dist s3://${{ secrets.S3_BUCKET }} --delete
      
      - name: Invalidate CloudFront
        run: |
          aws cloudfront create-invalidation \
            --distribution-id ${{ secrets.CLOUDFRONT_ID }} \
            --paths "/*"

Build and Push Docker Image

docker.yml
name: Docker Build

on:
  push:
    branches: [main]

jobs:
  docker:
    runs-on: ubuntu-latest
    
    steps:
      - uses: actions/checkout@v4
      
      - name: Login to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_TOKEN }}
      
      - name: Build and Push
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: |
            myuser/myapp:latest
            myuser/myapp:${{ github.sha }}

Deploy to Kubernetes

k8s.yml
name: Deploy to Kubernetes

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    
    steps:
      - uses: actions/checkout@v4
      
      - name: Configure kubectl
        uses: azure/k8s-set-context@v3
        with:
          kubeconfig: ${{ secrets.KUBE_CONFIG }}
      
      - name: Deploy
        run: |
          kubectl set image deployment/myapp \
            myapp=myregistry/myapp:${{ github.sha }}
          kubectl rollout status deployment/myapp

Best Practices

  • Use specific action versions (actions/checkout@v4, not @main)
  • Cache dependencies to speed up builds
  • Use matrix builds for multi-platform testing
  • Store secrets in GitHub Secrets, never in code
  • Use environment protection rules for production
  • Add status badges to your README

FAQ

How much does GitHub Actions cost?

Free for public repos. Private repos get 2,000 minutes/month free, then $0.008/minute for Linux runners.

Can I run workflows locally?

Yes! Use the "act" tool to run GitHub Actions locally for testing.

Need Help Setting Up CI/CD?

CloudElevate specializes in CI/CD pipeline design and implementation. We've built hundreds of GitHub Actions workflows for teams of all sizes.

Contact us at info@cloudelevate.ai to accelerate your DevOps journey.

Tagged with

GitHub ActionsCI/CDDevOpsAutomationGitHubDeploymentTestingWorkflows

Ready to elevate your cloud infrastructure?

Get a free consultation with our DevOps experts.

View Services