Why GitHub Actions?
GitHub Actions has eaten a large portion of the CI/CD market because it is free for open source, reasonably priced for private repos, deeply integrated with the GitHub developer workflow, and has a marketplace of 15,000+ pre-built actions. If your code is on GitHub, Actions is almost always the right first choice.
Understanding the Core Concepts
A workflow is a YAML file in .github/workflows/. Each workflow is triggered by one or more events (push, pull request, schedule, manual dispatch). A workflow contains jobs, each job runs on a fresh virtual machine, and each job has steps that either run shell commands or use pre-built actions.
Laravel Test Workflow
name: Tests
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
services:
mysql:
image: mysql:8.0
env:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: testing
ports: ["3306:3306"]
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: "8.3"
extensions: mbstring, pdo_mysql
- name: Install dependencies
run: composer install --no-interaction --prefer-dist
- name: Run tests
run: php artisan test --parallel
env:
DB_HOST: 127.0.0.1
DB_DATABASE: testing
DB_USERNAME: root
DB_PASSWORD: rootStoring Secrets Securely
Never put API keys, passwords, or SSH keys in your workflow YAML. Use GitHub Secrets (Settings > Secrets and Variables > Actions) to store sensitive values as ${{ secrets.YOUR_SECRET }}. These are encrypted at rest and never appear in workflow logs.
Caching Dependencies for Speed
- name: Cache Composer packages
uses: actions/cache@v4
with:
path: vendor
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}Adding a cache step for Composer reduces workflow run time from ~90 seconds to ~20 seconds for a typical Laravel project. The cache key includes a hash of composer.lock, so it automatically invalidates when dependencies change.