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:
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 buildWorkflow Triggers (Events)
GitHub Actions supports many trigger events:
# 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:
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 testUsing Secrets and Environment Variables
Store sensitive data like API keys in GitHub Secrets:
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-bucketArtifacts and Caching
Saving Build Artifacts
Share files between jobs or download them later:
- name: Build
run: npm run build
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: build-output
path: dist/
retention-days: 7Caching Dependencies
Speed up workflows by caching npm packages:
- 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
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
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
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/myappBest 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
Ready to elevate your cloud infrastructure?
Get a free consultation with our DevOps experts.