TL;DR: GitHub Actions is an automation platform built into GitHub. You write workflows in YAML files that run automatically when events happen in your repo (push, PR, schedule). The most common use is CI/CD: automatically running tests when you push code and deploying to production when tests pass. It's free for public repos and 2,000 minutes/month for private repos.
Why AI Coders Need to Know This
Manual deployment is a liability. Every time you deploy by hand, there's a chance you forget a step, push untested code, or deploy to the wrong environment. GitHub Actions eliminates that risk by automating the entire process: push code → tests run → if tests pass → code deploys. That loop is called CI/CD (Continuous Integration and Continuous Deployment).
When you ask AI to "help me deploy my app automatically," it will create a .github/workflows/ directory with YAML files. YAML is a configuration language that uses indentation to define structure — it's readable, but it's strict about formatting. One wrong indent and your workflow breaks silently. Understanding the structure is essential for troubleshooting.
Real Scenario
Prompt I Would Type
Set up GitHub Actions for my Next.js app. I want:
- Run tests automatically on every pull request
- Deploy to my VPS automatically when I push to main branch
- Send me a notification if the deployment fails
My VPS uses SSH. I'll provide the SSH key as a secret.
Here's what Claude generates and what every section means.
What AI Generated
# .github/workflows/deploy.yml
# This file defines an automated pipeline triggered by events in your repo
name: Test and Deploy # displayed in GitHub's Actions tab
on: # what events trigger this workflow
push:
branches: [main] # run when code is pushed to the main branch
pull_request:
branches: [main] # also run on PRs targeting main
jobs: # a workflow has one or more jobs
test: # job name — can be anything descriptive
runs-on: ubuntu-latest # which OS to run on (GitHub provides this VM for free)
steps: # ordered list of steps within this job
- name: Checkout code
uses: actions/checkout@v4 # official action that clones your repo onto the runner
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '22' # which Node.js version to use
cache: 'npm' # cache node_modules to speed up future runs
- name: Install dependencies
run: npm ci # npm ci is faster and more reliable than npm install in CI
- name: Run tests
run: npm test # whatever your test command is
- name: Build
run: npm run build # verify the production build succeeds
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }} # secrets from GitHub → Settings → Secrets
deploy:
needs: test # this job only runs if the 'test' job passes
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main' # only deploy on pushes to main (not on PRs)
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Deploy via SSH
uses: appleboy/ssh-action@v1 # a community action that handles SSH connections
with:
host: ${{ secrets.VPS_HOST }} # your VPS IP address (stored as a secret)
username: ${{ secrets.VPS_USER }} # your VPS username
key: ${{ secrets.SSH_PRIVATE_KEY }} # your SSH private key (stored as a secret)
script: |
cd /var/www/your-app
git pull origin main # pull latest code
npm ci --production # install production dependencies only
npm run build # rebuild
pm2 restart your-app # restart the app process (pm2 manages Node processes)
- name: Notify on failure
if: failure() # only runs if a previous step failed
uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: '❌ Deployment failed! Check the Actions tab for details.'
})
Understanding Each Part
Triggers (on:)
The on: block defines what events start the workflow. push: branches: [main] means "run this when someone pushes to the main branch." pull_request: branches: [main] means "run this when a PR is opened or updated that targets main." You can also use schedule: with a cron expression to run on a timer, or workflow_dispatch: to trigger manually from the GitHub UI.
Jobs and Steps
A workflow has one or more jobs. Each job runs on a separate runner (virtual machine) and has ordered steps. Steps run sequentially within a job; jobs can run in parallel by default, or sequentially with needs:. Each step either runs a shell command (run:) or uses a pre-built action (uses:).
Actions (uses:)
Actions are reusable automation units — essentially functions that do common things. actions/checkout@v4 (official GitHub action) clones your repo. actions/setup-node@v4 installs Node.js. appleboy/ssh-action is a community action that handles SSH connections. You find actions in the GitHub Marketplace. Always pin to a specific version (@v4, not @latest) so updates don't break your pipeline.
Secrets (${{ secrets.NAME }})
You never hardcode sensitive values in workflow files — they'd be visible in your repository. Instead, add secrets in GitHub: repository → Settings → Secrets and variables → Actions. Then reference them as ${{ secrets.SECRET_NAME }}. Secrets are encrypted at rest, masked in logs (shown as ***), and only accessible to workflow runs.
needs: — Job Dependencies
needs: test means the deploy job only starts after the test job completes successfully. If tests fail, deployment never runs. This is the core safety mechanism of CI/CD — broken code can't accidentally reach production.
What AI Gets Wrong About GitHub Actions
1. YAML Indentation Errors
YAML is indentation-sensitive and uses spaces (not tabs). One extra space or a missing space and the workflow fails to parse. AI occasionally generates YAML with subtle indentation inconsistencies that cause cryptic errors like "Invalid workflow file." Use a YAML linter or GitHub's workflow editor to validate before pushing.
2. Pinning Actions to Outdated Versions
AI training data has a knowledge cutoff. It sometimes generates workflows using outdated action versions (actions/checkout@v2 when v4 is current). Outdated actions may have known vulnerabilities or deprecated features. Check the GitHub Marketplace for current versions.
3. Missing Permissions
GitHub Actions workflows run with limited permissions by default. If your workflow needs to comment on PRs, push to branches, or interact with the GitHub API, you need to explicitly grant permissions using the permissions: block. AI sometimes forgets this, resulting in 403 errors when the workflow tries to write to the repo.
4. Running Expensive Steps on Every PR
AI sometimes generates workflows that run full production builds and heavy integration tests on every commit. For large projects, this can eat through your free minutes quickly. Use path filters (paths:) to only trigger workflows when relevant files change, and cache aggressively with actions/cache.
How to Debug GitHub Actions with AI
In Cursor
Paste your failing workflow YAML and the error from the Actions tab: "This GitHub Actions workflow fails with this error. Here's the YAML and the log output. What's wrong?" Cursor is particularly good at spotting YAML indentation problems and missing env: or permissions: blocks.
In Windsurf
For complex multi-job pipelines: "Review all workflow files in .github/workflows/ and identify any security issues, inefficiencies, or patterns that could cause flaky runs." Windsurf's codebase-wide context is useful for auditing workflows holistically.
In Claude Code
Claude is excellent at explaining what a workflow does line by line: "Explain this GitHub Actions workflow as if I've never used CI/CD before. What does each block do, and what would I see in the GitHub UI when it runs?" Also useful for generating the permissions: blocks you need for specific GitHub API operations.
General Debugging Tips
- Add
- run: echo "Step reached"between steps to find where the workflow breaks - Use the "Re-run failed jobs" button in GitHub's Actions tab without pushing new code
- Check the runner's environment with
- run: env | sortto see all available variables - Use
act(a CLI tool) to run GitHub Actions locally before pushing
What to Learn Next
Frequently Asked Questions
GitHub Actions is an automation platform built into GitHub. It lets you run code (called workflows) automatically in response to events in your repository — like pushing code, opening a pull request, or on a schedule. It's most commonly used for CI/CD: automatically testing code and deploying it to production.
CI/CD stands for Continuous Integration and Continuous Deployment. CI means automatically testing every code change when it's pushed. CD means automatically deploying tested code to production. Together they reduce manual deployment steps and catch bugs before they reach users.
GitHub Actions is free for public repositories with unlimited minutes. Private repositories get 2,000 free minutes per month on the free plan, and 3,000 minutes on Pro. Each workflow run costs minutes based on the runner type — Linux is cheapest, macOS costs 10x more per minute.
A runner is the server that executes your workflow. GitHub provides hosted runners (virtual machines running Ubuntu, Windows, or macOS) that spin up fresh for each workflow run. You can also use self-hosted runners on your own servers for more control or to avoid minute limits.
Go to your repository on GitHub → Settings → Secrets and variables → Actions → New repository secret. Add a name (like DEPLOY_KEY) and value. Reference it in your workflow YAML as ${{ secrets.DEPLOY_KEY }}. Secrets are encrypted and never appear in logs.