Skip to main content

What is GitHub Actions?

What is CI/CD?

Before understanding GitHub Actions, it helps to understand the problem it solves.

Without CI/CD, the release process looks like this:

  1. Developer writes code locally
  2. Manually runs tests (maybe)
  3. Manually builds the app
  4. SSHs into the server and manually deploys

This is slow, error-prone, and doesn't scale with a team.

With CI/CD, every code push automatically:

  1. Runs all tests
  2. Builds the app
  3. Deploys if tests pass

GitHub Actions automates this pipeline directly from your GitHub repository.

Core Concepts

Workflow

A workflow is an automated process defined in a YAML file stored at .github/workflows/<name>.yml. A repo can have multiple workflows (e.g., one for CI on every push, one for deployment on merge to main).

Trigger (on)

The trigger defines what event starts the workflow:

on:
push:
branches: [main] # runs when code is pushed to main
pull_request: # runs on every PR
schedule:
- cron: '0 0 * * *' # runs daily at midnight UTC
workflow_dispatch: # manual trigger from the GitHub UI

Job

A job is a set of steps that run on the same machine. Jobs run in parallel by default. You can add needs to make one job wait for another.

jobs:
test:
runs-on: ubuntu-latest
steps: [...]

deploy:
needs: test # deploy only runs if test passes
runs-on: ubuntu-latest
steps: [...]

Step

A step is a single task within a job — either a shell command (run) or a pre-built action (uses).

steps:
- uses: actions/checkout@v4 # action: checks out your repo code
- uses: actions/setup-node@v4 # action: installs Node.js
with:
node-version: '20'
- run: npm install # shell command
- run: npm test # shell command

Runner

A runner is the machine that executes the job. GitHub provides hosted runners:

  • ubuntu-latest — most common, fast, free
  • windows-latest — for Windows-specific builds
  • macos-latest — for iOS/Mac builds

You can also use self-hosted runners — your own server registered with GitHub Actions.

Action

An action is a reusable step published to the GitHub Marketplace. Instead of writing 20 lines of shell to set up Node.js, you use actions/setup-node@v4 in one line. Popular actions include:

ActionPurpose
actions/checkoutClone your repo into the runner
actions/setup-nodeInstall a specific Node.js version
docker/build-push-actionBuild and push Docker images
appleboy/ssh-actionSSH into a remote server and run commands

A Minimal CI Workflow

name: CI

on:
push:
branches: [main]
pull_request:

jobs:
test:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: '20'

- run: npm ci

- run: npm test

Save this as .github/workflows/ci.yml and push it. Every subsequent push or PR to main will automatically run your tests.

Secrets

Never hardcode API keys, passwords, or SSH keys in workflow files. Store them as secrets in your repo settings (Settings → Secrets and variables → Actions) and reference them in workflows:

- run: npm run deploy
env:
API_KEY: ${{ secrets.API_KEY }}
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}

Secrets are masked in logs — they never appear in plain text.