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_DEBUGtotrue. - Use
actto run workflows locally before pushing — install from the act GitHub repository.
