CI/CD with GitHub Actions
Workflow files for GitHub Actions: triggers, jobs, steps, secrets, caching, matrices and reuse.
A workflow file
Save it as .github/workflows/ci.yml.
name: CI on: push: branches: [main] pull_request: jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: npm ci && npm testThe smallest useful pipeline: test on every push and pull request
permissions: contents: readGive the workflow only the access it needs
concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: trueCancel an older run of the same branch when a new one starts
Triggers
on: [push, pull_request]On pushes and pull requests
on: schedule: - cron: "0 6 * * 1"On a schedule (UTC): Mondays at 06:00
on: workflow_dispatch: inputs: env: { type: choice, options: [staging, prod] }A manual "Run workflow" button with an input
on: push: paths: ["src/**"] tags: ["v*"]Only for some paths, or for version tags
on: workflow_call:Make this workflow reusable by other workflows
Jobs and steps
needs: [build, test]Run a job only after others succeed
if: github.ref == 'refs/heads/main'Run a job or step only in some cases
strategy: matrix: node: [18, 20, 22] steps: - uses: actions/setup-node@v4 with: { node-version: "${{ matrix.node }}" }The same job on several versions at once
timeout-minutes: 15Stop a job that hangs
continue-on-error: trueDo not fail the workflow if this step fails
defaults: run: working-directory: appSet the folder for every run step
- name: Show the context run: echo "$GITHUB_SHA on $GITHUB_REF_NAME"Built-in environment variables
Secrets, variables and outputs
env: API_KEY: ${{ secrets.API_KEY }}Use a repository secret (it is masked in logs)
${{ vars.REGION }}A non-secret configuration variable
echo "version=1.2.3" >> "$GITHUB_OUTPUT"Set a step output; read it as ${{ steps.<id>.outputs.version }}
echo "$HOME/bin" >> "$GITHUB_PATH"Add a folder to PATH for the next steps
environment: productionUse an environment: its secrets and required approvals
permissions: id-token: write contents: readAllow OIDC login to a cloud provider, with no stored cloud keys
Caching and artifacts
- uses: actions/setup-node@v4 with: { node-version: 20, cache: npm }Cache the npm download folder
- uses: actions/cache@v4 with: path: ~/.cache/pip key: pip-${{ hashFiles('requirements.txt') }}Cache anything, keyed on a file's hash
- uses: actions/upload-artifact@v4 with: { name: report, path: report/ }Keep files from a run
- uses: actions/download-artifact@v4 with: { name: report }Use them in a later job
Build and ship
- uses: docker/build-push-action@v6 with: push: true tags: ghcr.io/${{ github.repository }}:${{ github.sha }}Build and push a container image
jobs: call: uses: org/repo/.github/workflows/deploy.yml@main with: { env: staging } secrets: inheritCall a reusable workflow
- run: gh release create "$GITHUB_REF_NAME" --generate-notes env: { GH_TOKEN: "${{ github.token }}" }Create a release from a tag
actions/checkout@<full commit SHA>Pin third-party actions to a commit, not a moving tag
Nothing matches that search.
Cheatsheet for the CI/CD with GitHub Actions path · Deboistech · All cheatsheets