This page gives you clean, production-ready CI/CD workflows you can paste directly into your repository. Each workflow is minimal, fast, and built around real-world usage: Node builds, PHP tests (Pest/PHPUnit), Python testing, Docker build/push, matrix strategies, and caching.
Use these as boilerplates or as reference setups when building your own automation pipelines.
Node.js (build/test)
name: Node CI
on:
push:
branches: [ main ]
pull_request:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- run: npm ci
- run: npm run build --if-present
- run: npm test
PHP (Pest/PHPUnit) — Composer + Extensions
name: PHP CI
on:
push:
branches: [ main ]
pull_request:
jobs:
tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
extensions: mbstring, intl, pdo_mysql
coverage: none
- name: Cache Composer
uses: actions/cache@v4
with:
path: vendor
key: composer-${{ hashFiles('composer.lock') }}
- name: Install dependencies
run: composer install --prefer-dist --no-progress
- name: Run tests
run: ./vendor/bin/pest || ./vendor/bin/phpunit
Python (pytest)
name: Python CI
on:
push:
branches: [ main ]
pull_request:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
cache: 'pip'
- run: pip install -r requirements.txt
- run: pytest -q
Docker Build & Push (GHCR)
name: Docker Build & Push
on:
push:
branches: [ main ]
jobs:
docker:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build & push
uses: docker/build-push-action@v5
with:
push: true
tags: |
ghcr.io/${{ github.repository }}/app:latest
ghcr.io/${{ github.repository }}/app:${{ github.sha }}
Matrix Builds (Multi-Version Node Example)
name: Node Matrix
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node: [18, 20, 22]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
cache: 'npm'
- run: npm ci
- run: npm test
Cache Snippets (npm / composer / pip)
npm cache:
- uses: actions/cache@v4
with:
path: node_modules
key: npm-${{ hashFiles('package-lock.json') }}
composer cache:
- uses: actions/cache@v4
with:
path: vendor
key: composer-${{ hashFiles('composer.lock') }}
pip cache:
- uses: actions/cache@v4
with:
path: ~/.cache/pip
key: pip-${{ hashFiles('requirements.txt') }}
FAQ
Self-hosted vs GitHub-hosted runners?
GitHub-hosted runners are fast, reliable, and ideal for 95% of repositories.
Self-hosted makes sense only for heavy builds, private infrastructure, or large workflow volumes.
How to cache npm/pip/composer properly?
Use actions/cache with lockfile hashing — this ensures cache invalidation when dependencies change.
Secrets management best practices?
Never hardcode secrets in YAML.
Use GitHub Secrets + environment-level protections (required reviewers, restricted deployments).