Github Actions Advanced

Production engineering guide for github actions advanced covering patterns, implementation strategies, and operational best practices.

This reference covers complex patterns and failure modes in GitHub Actions workflows, focusing on execution behavior, artifact handling, and configuration nuances that affect production reliability. These patterns matter when building workflows that must handle edge cases, maintain consistency across environments, or integrate with external systems.

Workflow Execution Control

Conditional Step Execution with Complex Logic

GitHub Actions uses if expressions in step definitions to control execution flow. The expression syntax supports logical operators and built-in functions like github.event, job.status, and steps.

- name: Deploy to staging
  if: github.ref == 'refs/heads/main' && github.event_name == 'push'
  run: |
    echo "Deploying to staging environment"
    deploy-staging.sh

- name: Run tests only on pull requests
  if: github.event_name == 'pull_request'
  run: |
    echo "Running tests for PR #${{ github.event.pull_request.number }}"
    run-tests.sh

The if condition evaluates in the context of the current step. A common failure occurs when using github.ref instead of github.base_ref or github.head_ref. The expression github.ref == 'refs/heads/main' fails for pull request merges because github.ref refers to the target branch, not the source.

Job Dependencies and Status Checks

Jobs in a workflow can depend on each other using the needs field. The dependency system evaluates job status, but it's important to understand that needs waits for all dependencies to complete successfully, not just start.

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - run: echo "Building"
  
  test:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - run: echo "Testing"

  deploy:
    needs: [build, test]
    runs-on: ubuntu-latest
    steps:
      - run: echo "Deploying"

If test fails, deploy will not run even though it's configured to depend on both jobs. The workflow will show deploy as skipped rather than failed.

Matrix Strategy with Complex Dimensions

The matrix strategy creates parallel jobs with different parameter combinations. When using multiple dimensions, the system generates a Cartesian product of all values.

strategy:
  matrix:
    node-version: [14.x, 16.x]
    os: [ubuntu-latest, windows-latest]
    include:
      - os: ubuntu-latest
        node-version: 18.x

Each combination runs as a separate job. The system treats the final matrix as a single job that fails if any matrix job fails. Matrix jobs do not share environment variables unless explicitly configured.

Artifact Management

Uploading and Downloading Artifacts with Size Limits

Artifacts can be uploaded from workflow steps using the actions/upload-artifact action. The maximum artifact size is 10 GB per upload, with a total limit of 50 GB per workflow run.

- name: Upload build artifacts
  uses: actions/upload-artifact@v3
  with:
    name: build-output
    path: |
      dist/
      build.log
    retention-days: 7

The path parameter accepts multiple patterns, each on a separate line. The upload process fails if the total artifact size exceeds limits, but the failure is silent at the upload step level.

Artifact Download with Specific File Selection

Downloading artifacts uses the actions/download-artifact action with pattern matching.

- name: Download specific files
  uses: actions/download-artifact@v3
  with:
    name: build-output
    path: ./output/

The download preserves directory structure but does not preserve file permissions or extended attributes. A common failure mode occurs when artifacts are uploaded from one platform and downloaded on another, leading to permission mismatches.

Artifact Lifecycle Management

Artifacts can be configured to expire after a set number of days using retention-days. This setting applies to all artifacts in a workflow run, not individual uploads.

- name: Upload with retention
  uses: actions/upload-artifact@v3
  with:
    name: logs
    path: logs/
    retention-days: 30

If retention-days is not set, the default is 90 days. Artifacts are deleted automatically after the retention period, but this deletion is not logged in workflow output.

Environment and Secret Management

Environment Variables in Workflows

Environment variables can be set in multiple ways: at the job level, step level, or globally for a workflow. The env key at the workflow level sets variables for all jobs.

env:
  NODE_ENV: production
  API_URL: https://api.example.com

jobs:
  deploy:
    runs-on: ubuntu-latest
    env:
      DEPLOY_ENV: staging
    steps:
      - run: echo $NODE_ENV
      - run: echo $DEPLOY_ENV

Variables set in env at the workflow level are available to all jobs, while job-level variables override workflow-level ones. The system evaluates variable references at runtime, not at parse time.

Secret Configuration and Encryption

Secrets are configured in the GitHub repository settings under "Secrets and variables" > "Actions". Secrets are encrypted using GitHub's encryption keys before storage and decrypted at runtime.

- name: Deploy with secrets
  env:
    API_TOKEN: ${{ secrets.API_TOKEN }}
  run: |
    curl -H "Authorization: Bearer $API_TOKEN" https://api.example.com/deploy

Secrets are not available in the workflow YAML itself. They must be referenced using ${{ secrets.SECRET_NAME }}. If a secret is referenced but not defined, the step fails with an error like Error: Secret 'SECRET_NAME' not found.

Environment Protection Rules

Environments can have protection rules that control when workflows can deploy to them.

jobs:
  deploy:
    environment:
      name: production
      url: https://app.example.com

The workflow waits for environment approval before running. If no approval is configured, the deployment proceeds immediately. Environment URLs are displayed in workflow logs but do not affect execution behavior.

Workflow Trigger Configuration

Custom Event Triggers

Workflows can be triggered by custom events using workflow_dispatch or by webhook payloads.

on:
  workflow_dispatch:
    inputs:
      environment:
        description: 'Environment to deploy'
        required: true
        default: 'staging'

The workflow_dispatch event allows manual triggering of workflows with parameters. The system validates input types and requires defined defaults for optional parameters.

Scheduled Workflows

Scheduled workflows use cron expressions to trigger at specific times.

on:
  schedule:
    - cron: '0 2 * * *'

The cron expression runs in UTC timezone, not the repository's local time zone. The system evaluates the expression against UTC time. If a scheduled workflow fails, it does not retry automatically.

Repository Event Triggers

Workflows can be triggered by various repository events including pushes, pull requests, and issues.

on:
  push:
    branches: [ main ]
    paths: [ 'src/**' ]
  pull_request:
    branches: [ main ]
    types: [ opened, synchronize ]

The paths filter works on the changed files, not the complete repository state. If a file is modified but not included in the path filter, the workflow does not trigger even if other files change.

Advanced Job Configuration

Custom Runner Labels and Resource Allocation

Jobs can specify runner labels to target specific infrastructure.

jobs:
  build:
    runs-on: [self-hosted, linux, x64]
    steps:
      - run: echo "Running on custom runner"

The system selects runners based on label matching. If no runner matches the specified labels, the job waits for a matching runner or fails if none is available.

Job Timeout Configuration

Job timeouts can be configured using the timeout-minutes setting.

jobs:
  long-running:
    timeout-minutes: 60
    runs-on: ubuntu-latest
    steps:
      - run: |
          echo "This job will timeout after 60 minutes"
          sleep 3600

The timeout applies to the entire job execution, not individual steps. If a job times out, it is marked as failed but does not retry automatically.

Step-Level Resource Management

Steps can specify resource requirements using with parameters.

- name: Run with resources
  uses: actions/checkout@v3
  with:
    fetch-depth: 0

The fetch-depth parameter controls how many commits are fetched during checkout. Setting it to 0 fetches all commits, which is useful for Git history operations.

Error Handling and Debugging

Step Failure Behavior

Steps that fail cause the workflow to stop unless explicitly configured otherwise.

- name: Run with error handling
  continue-on-error: true
  run: |
    echo "This step can fail"
    exit 1

The continue-on-error flag allows a workflow to continue even if a step fails. If multiple steps fail, the overall job status is failed.

Workflow Failure Detection

Workflow failures are detected by step exit codes and error messages. The system treats non-zero exit codes as failures.

- name: Fail gracefully
  run: |
    echo "Processing failed"
    exit 1

The workflow logs show detailed error information including stack traces and environment state. Errors during artifact upload do not cause the overall workflow to fail unless explicitly configured.

Debugging with Environment Variables

Debugging workflows can be enabled using environment variables.

- name: Enable debug
  run: |
    echo "DEBUG mode enabled"
    ls -la

The system sets several built-in variables including GITHUB_WORKFLOW, GITHUB_RUN_ID, and GITHUB_ACTOR. These are available in all steps and can be used for logging or conditional behavior.

Production Considerations

Resource Constraints and Limits

GitHub Actions has specific resource constraints that affect workflow execution. Each job runs with limited CPU and memory resources, and the system enforces maximum run times.

jobs:
  memory-intensive:
    runs-on: ubuntu-latest
    steps:
      - run: |
          # This operation might exceed available memory
          echo "Memory intensive task"

Jobs running on shared runners have limited resources compared to self-hosted runners. The system does not provide detailed resource usage information in logs.

Failure Recovery Patterns

Workflows can be configured to retry failed steps or jobs.

- name: Retryable step
  uses: actions/checkout@v3
  with:
    fetch-depth: 0
  retry: 2

The retry logic applies only to the specific action, not the entire workflow. If a workflow fails due to external conditions, it may need manual intervention.

Performance Optimization

Workflow performance can be improved by reducing step count and optimizing artifact usage.

- name: Combined steps
  run: |
    echo "Step 1"
    echo "Step 2"
    echo "Step 3"

Combining multiple operations in a single step reduces overhead. Large artifacts cause longer upload/download times, affecting workflow duration.

This page was rewritten on 15 October 2026. It replaced a templated version that was not specific to its own title. How these pages are written and checked. If anything here is wrong, tell us at [email protected] and we will correct it.