Overview

GitHub Actions lets you automate building, testing, and deploying code directly from your GitHub repository. This tutorial walks through creating a CI/CD pipeline for a Node.js application, from first workflow file to automated Docker image build.

What Is a GitHub Actions Workflow?

A workflow is a YAML file stored in .github/workflows/ inside your repository. It defines one or more jobs, each running on a virtual machine called a runner. Workflows trigger on events such as push, pull_request, or a schedule.

Core Concepts

Concept Description
Workflow A YAML file that defines automation
Job A set of steps that run on the same runner
Step A single task, either a shell command or a reusable action
Action A reusable unit of code published on GitHub Marketplace
Runner The virtual machine that executes a job

Step 1: Create the Workflow File

Create .github/workflows/ci.yml in your repository:

name: CI Pipeline

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

jobs:
  build-and-test:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

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

      - name: Install dependencies
        run: npm ci

      - name: Run tests
        run: npm test

This workflow runs on every push to main and every pull request targeting main. It checks out the code, installs Node.js 20 with npm caching, installs dependencies, and runs tests.

Step 2: Add a Build Job

Extend the workflow to build a Docker image after tests pass:

  docker-build:
    needs: build-and-test
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Build Docker image
        run: docker build -t my-app:${{ github.sha }} .

      - name: Smoke test container
        run: |
          docker run -d --name smoke -p 3000:3000 my-app:${{ github.sha }}
          sleep 5
          curl -f http://localhost:3000/health || exit 1
          docker stop smoke

The needs: build-and-test keyword ensures the Docker build only runs after tests succeed.

Step 3: Store Secrets Securely

Never hardcode credentials. Add secrets in GitHub under Settings → Secrets and variables → Actions, then reference them:

      - name: Log in to container registry
        run: echo "${{ secrets.REGISTRY_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin

Common Triggers

Trigger Syntax
Push to a branch on: push: branches: [main]
Pull request on: pull_request: branches: [main]
Manual trigger on: workflow_dispatch
Schedule on: schedule: - cron: '0 2 * * *'
Tag push on: push: tags: ['v*']

Debugging Failed Workflows

  • Check the Actions tab in your repository for logs.
  • Enable debug logging by setting the repository secret ACTIONS_STEP_DEBUG to true.
  • Use act to run workflows locally before pushing — install from the act GitHub repository.