GitHub Actions Basics
GitHub Actions is a powerful automation platform that allows you to build, test, and deploy your code directly from GitHub. It enables continuous integration and continuous deployment (CI/CD) workflows without leaving your repository.
What are GitHub Actions?
GitHub Actions automate tasks in your software development lifecycle. You can use them to run tests, deploy applications, send notifications, and much more - all triggered by events in your repository.
Key Benefit: GitHub Actions is free for public repositories with unlimited minutes. Private repositories get 2,000 free minutes per month on the free plan.
Core Concepts
Understanding these components is essential:
Workflow:
- Automated process defined in YAML file
- Stored in .github/workflows/ directory
- Contains one or more jobs
Event (Trigger):
- Specific activity that starts a workflow
- Examples: push, pull_request, schedule, manual
Job:
- Set of steps that run on the same runner
- Jobs run in parallel by default
- Can be configured to run sequentially
Step:
- Individual task within a job
- Runs a command or an action
- Steps run sequentially within a job
Action:
- Reusable unit of code
- Can be from GitHub Marketplace or custom
- Building blocks of steps
Runner:
- Server that runs your workflows
- GitHub-hosted or self-hosted
- Available for Linux, Windows, macOS
Your First Workflow
Let's create a simple workflow that runs on every push:
# Create workflow directory
mkdir -p .github/workflows
# Create workflow file
cat > .github/workflows/hello-world.yml <<'EOF'
name: Hello World
# When to run this workflow
on:
push:
branches: [ main ]
# Jobs to run
jobs:
greet:
runs-on: ubuntu-latest
steps:
- name: Print greeting
run: echo "Hello, GitHub Actions!"
- name: Print date
run: date
EOF
# Commit and push
git add .github/workflows/hello-world.yml
git commit -m "Add Hello World workflow"
git push
After pushing, check the Actions tab on GitHub to see your workflow run!
Pro Tip: Workflow files must be in the .github/workflows/ directory and have a .yml or .yaml extension.
Common Workflow Triggers
Configure when your workflows should run:
# Run on push to main branch
on:
push:
branches: [ main ]
# Run on pull request
on:
pull_request:
branches: [ main ]
# Run on multiple events
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
# Run on schedule (cron)
on:
schedule:
- cron: '0 0 * * *' # Daily at midnight
# Run manually
on:
workflow_dispatch:
# Run on specific paths
on:
push:
paths:
- 'src/**'
- 'tests/**'
Basic CI Workflow (Testing)
A practical workflow that runs tests on every push:
name: CI - Run Tests
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
steps:
# Checkout repository code
- name: Checkout code
uses: actions/checkout@v4
# Setup Node.js environment
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
# Install dependencies
- name: Install dependencies
run: npm ci
# Run tests
- name: Run tests
run: npm test
# Run linter
- name: Run linter
run: npm run lint
Understanding uses: The uses keyword runs an action from GitHub Marketplace or a repository. The run keyword executes shell commands.
Multiple Jobs in Parallel
Run different jobs simultaneously:
name: Build and Test
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build application
run: npm run build
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run tests
run: npm test
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run linter
run: npm run lint
Sequential Jobs with Dependencies
Make jobs run in a specific order:
name: Build, Test, Deploy
on:
push:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run build
test:
needs: build # Wait for build to complete
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm test
deploy:
needs: [build, test] # Wait for both
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm run deploy
Important: Jobs run in parallel by default. Use needs to create dependencies and ensure sequential execution.
Using Matrix Strategy
Test across multiple versions or platforms:
name: Test Matrix
on: [push]
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
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm test
This creates 9 jobs (3 OS × 3 Node versions) that run in parallel!
Environment Variables and Secrets
Use environment variables and secrets securely:
name: Deploy with Secrets
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
env:
NODE_ENV: production
API_URL: https://api.example.com
steps:
- uses: actions/checkout@v4
- name: Deploy to server
env:
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
API_TOKEN: ${{ secrets.API_TOKEN }}
run: |
echo "Deploying to production..."
# Use $DEPLOY_KEY and $API_TOKEN securely
Adding Secrets: Go to repository Settings → Secrets and variables → Actions → New repository secret. Secrets are encrypted and never exposed in logs.
Conditional Steps
Run steps only when conditions are met:
name: Conditional Workflow
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run on main only
if: github.ref == 'refs/heads/main'
run: echo "This is the main branch"
- name: Run on PR only
if: github.event_name == 'pull_request'
run: echo "This is a pull request"
- name: Run on success
if: success()
run: echo "Previous steps succeeded"
- name: Run on failure
if: failure()
run: echo "Previous steps failed"
Caching Dependencies
Speed up workflows by caching dependencies:
name: Build with Cache
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
# Cache node_modules
- name: Cache dependencies
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- run: npm ci
- run: npm run build
Cache Benefits: Caching can reduce workflow execution time by 40-60% by avoiding re-downloading dependencies on every run.
Status Badges
Add workflow status badges to your README:
# Badge URL format:
https://github.com/{owner}/{repo}/actions/workflows/{workflow-file}/badge.svg
# Example in README.md:

# With branch specification:

GitHub Marketplace Actions
Popular actions you can use in your workflows:
Essential Actions:
# Checkout code
- uses: actions/checkout@v4
# Setup programming languages
- uses: actions/setup-node@v4
- uses: actions/setup-python@v5
- uses: actions/setup-java@v4
- uses: actions/setup-go@v5
# Upload/Download artifacts
- uses: actions/upload-artifact@v4
- uses: actions/download-artifact@v4
# Deploy to GitHub Pages
- uses: peaceiris/actions-gh-pages@v4
# Send Slack notification
- uses: slackapi/slack-github-action@v1
# Docker build and push
- uses: docker/build-push-action@v5
Browse more actions at: https://github.com/marketplace?type=actions
Workflow Example: Deploy to GitHub Pages
A complete workflow for deploying a static site:
name: Deploy to GitHub Pages
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: npm ci
- name: Build site
run: npm run build
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./dist
Viewing Workflow Results
Check your workflow status on GitHub:
# On GitHub:
1. Go to your repository
2. Click "Actions" tab
3. See all workflow runs
4. Click any run to view details
5. Expand steps to see logs
# Workflow statuses:
✓ Success (green check)
✗ Failure (red X)
⊙ In progress (yellow circle)
○ Cancelled (grey circle)
− Skipped
Practical Exercise:
Task: Create a CI workflow for your project
- Create
.github/workflows/ci.yml in your repository
- Configure it to run on push and pull_request to main
- Add steps to:
- Checkout code
- Setup your language environment (Node, Python, etc.)
- Install dependencies
- Run tests
- Run linter (if available)
- Commit and push the workflow file
- View the workflow run in the Actions tab
- Add a status badge to your README
Expected Outcome: You'll have automated testing that runs on every push and pull request, with a visible status badge.
Best Practices
✓ Use specific action versions (@v4, not @main)
✓ Cache dependencies to speed up workflows
✓ Use secrets for sensitive data
✓ Set appropriate permissions (least privilege)
✓ Use matrix strategy for cross-platform testing
✓ Keep workflows focused and modular
✓ Add meaningful names to jobs and steps
✓ Use conditional execution to save resources
✓ Monitor workflow usage and costs
✓ Pin action versions for reproducibility
Troubleshooting Workflows
Common issues and solutions:
Problem: Workflow doesn't trigger
- Check file is in .github/workflows/
- Verify YAML syntax is valid
- Ensure trigger conditions are met
Problem: Permission denied
- Add required permissions to workflow
- Check repository secrets are set
- Verify token has correct scopes
Problem: Slow workflow
- Use caching for dependencies
- Run jobs in parallel
- Use matrix strategy efficiently
Problem: Tests fail in CI but pass locally
- Check environment differences
- Verify dependencies are installed
- Check environment variables
- Review workflow logs carefully
Summary
In this lesson, you learned:
- GitHub Actions automate CI/CD workflows directly in GitHub
- Workflows are YAML files in
.github/workflows/
- Key components: events, jobs, steps, actions, runners
- Common triggers: push, pull_request, schedule, workflow_dispatch
- Jobs run in parallel by default; use
needs for dependencies
- Matrix strategy tests across multiple configurations
- Secrets keep sensitive data secure
- GitHub Marketplace provides thousands of reusable actions
- Status badges show workflow status in your README
Next Up: In the next lesson, we'll explore Git Flow, a popular branching workflow for managing releases!