GitHub Actions Environmental Constants and Contextual Variables

The operational efficiency of a Continuous Integration and Continuous Deployment (CI/CD) pipeline depends heavily on the ability of the automation engine to understand its own state, the environment it is inhabiting, and the specific event that triggered its execution. In the ecosystem of GitHub Actions, this is achieved through a sophisticated architecture of default environment variables and context objects. These constants provide a standardized way for developers and DevOps engineers to inject dynamic data into their workflows without hardcoding values, ensuring that the same YAML configuration can function across different branches, repositories, and user accounts.

The system differentiates between variables that are automatically set by the GitHub runner environment and those that are accessed via the github context object. While they often mirror each other in the data they provide, their implementation differs. Environment variables are typically accessed via the shell (e.g., $GITHUB_REPOSITORY), whereas context variables are accessed via the GitHub expressions syntax (e.g., ${{ github.repository }}). This dual-layer approach allows for extreme flexibility, enabling conditional logic to be processed both at the workflow orchestration level and within the actual execution of scripts on the runner.

Default Runner Environment Variables

GitHub provides a comprehensive set of variables that are pre-configured in every runner environment. These are essential for differentiating between local execution and cloud-based automation, as well as for identifying the specific actor and repository involved in the process.

The following table delineates the primary environment variables available to all runners:

Variable Description Example/Value
CI Indicates if the job is running in a CI environment true
GITHUB_ACTIONS Specifically identifies if the workflow is running via GitHub Actions true
GITHUB_ACTOR The username of the person or app that initiated the workflow octocat
GITHUBACTORID The unique account ID of the triggering person or app 1234567
GITHUB_REPOSITORY The full owner and repository name octocat/Hello-World
GITHUBREPOSITORYID The unique identifier for the repository 123456789
GITHUBREPOSITORYOWNER The name of the repository owner octocat
GITHUBREPOSITORYOWNER_ID The account ID of the repository owner 1234567
GITHUB_REF The fully-formed ref of the branch or tag that triggered the run refs/heads/main
GITHUBREFTYPE The type of ref (branch or tag) branch
GITHUBREFPROTECTED Boolean indicating if branch protections are active true/false
GITHUBRUNID Unique number for a specific workflow run 1658821493
GITHUBRUNNUMBER Sequential number for a specific workflow 1, 2, 3...
GITHUBRUNATTEMPT Sequence number for re-runs of a specific run 1, 2, 3...
GITHUBRETENTIONDAYS Number of days logs and artifacts are stored 90
GITHUBAPIURL The base URL for the GitHub REST API https://api.github.com
GITHUBGRAPHQLURL The endpoint for the GitHub GraphQL API https://api.github.com/graphql
GITHUBEVENTNAME The specific event that triggered the workflow workflow_dispatch
GITHUBEVENTPATH Path to the JSON file containing the full event payload /github/workflow/event.json

Execution Context and Actor Identification

The variables GITHUB_ACTOR and GITHUB_ACTOR_ID are critical for auditing and permission management. The actor is the entity that started the workflow. This is distinct from the account ID, which is a persistent numeric identifier. Because usernames can change, the GITHUB_ACTOR_ID provides a stable reference for integration with external identity management systems.

The GITHUB_ACTIONS variable is particularly useful for test suites. By checking if this variable is set to true, a developer can instruct their test framework to use different configurations when running on a local machine versus the GitHub runner, such as using a different database connection string or skipping certain browser-based tests that require a GUI.

Repository and Reference Mapping

The GITHUB_REPOSITORY and GITHUB_REF variables allow for dynamic pathing. For instance, GITHUB_REF provides the exact branch or tag. In the case of pull requests that have not yet been merged, this variable follows a specific format: <pr_number>/merge. This allows scripts to identify exactly which merge commit is being tested.

The GITHUB_REF_TYPE variable simplifies logic by explicitly stating whether the trigger was a branch or a tag. This prevents the need for complex regex parsing of the GITHUB_REF string to determine if a release tag was used.

Workflow Run Metrics and Lifecycle

The distinction between GITHUB_RUN_ID, GITHUB_RUN_NUMBER, and GITHUB_RUN_ATTEMPT is vital for telemetry and logging.

  • The GITHUB_RUN_ID is a unique identifier for a specific execution. It remains constant even if the workflow is re-run.
  • The GITHUB_RUN_NUMBER is an incremental counter for the workflow overall.
  • The GITHUB_RUN_ATTEMPT tracks how many times a specific GITHUB_RUN_ID has been attempted.

This granularity allows engineers to create sophisticated logging systems where logs can be grouped by the overall run but separated by individual attempts to diagnose intermittent failures (flaky tests).

Action-Specific and Path Variables

When dealing with composite actions—actions that combine multiple steps—GitHub provides specialized variables to manage the filesystem and identify the action's origin.

  • GITHUB_ACTION: This identifies the action currently running. If a step is running a script without an explicit ID, the value defaults to __run. To prevent collisions when the same action or script is invoked multiple times within a single job, GitHub appends a sequence number. The first instance is __run, the second is __run_2, and so on. For official actions, the format is __repo-owner_name-of-action-repo.
  • GITHUBACTIONPATH: This variable is exclusive to composite actions. It provides the absolute path to the action's location on the runner, such as /home/runner/work/_actions/repo-owner/name-of-action-repo/v1. This is essential for referencing other files (like scripts or configuration files) located within the same repository as the action.
  • GITHUBACTIONREPOSITORY: This identifies the owner and repository of the action being executed, for example, actions/checkout. This allows the workflow to report which external dependencies are being utilized.

The GitHub Context Object

While environment variables are available to the shell, the github context object provides a structured way to access data within the YAML configuration itself. This object is passed to the workflow and can be used in if statements and expression evaluations.

Core Context Properties

The github context contains properties that overlap with environment variables but offer different programmatic advantages.

  • github.actor: The username of the user who triggered the initial workflow run. It is important to note that in the event of a re-run, this value may differ from github.triggering_actor. Regardless of who initiates the re-run, the workflow uses the privileges associated with github.actor.
  • github.actor_id: The numeric account ID of the person or app that triggered the run.
  • github.api_url: The URL for the GitHub REST API, allowing the workflow to make authenticated calls to the GitHub platform.
  • github.base_ref: This is specific to pull_request or pull_request_target events. It represents the target branch of the pull request.
  • github.event: This is a complex object containing the full webhook payload. It is identical to the payload sent by GitHub's webhooks, meaning every piece of data provided by the event (such as the commit message or the PR title) is accessible here.
  • github.action_status: In the context of a composite action, this returns the current result of the action.

Runner-Specific File Paths

GitHub utilizes temporary files to manage state between steps. These paths are exposed via both environment variables and the github context.

  • GITHUB_ENV / github.env: This is the path to a file used to set environment variables for subsequent steps. Each step in a job has a unique file to avoid collisions.
  • GITHUB_OUTPUT / github.output: This path points to the file used to set the current step's outputs. This allows a value calculated in one step to be used as an input in a later step.
  • GITHUB_PATH: This path is used to add new directories to the system PATH, ensuring that binaries installed during a workflow step are available to subsequent steps.

Conditional Logic and Control Flow

The true power of these constants is realized when they are used in if statements to control the execution flow of a workflow. By leveraging the context and environment variables, developers can create dynamic pipelines.

Implementing Conditional Steps

Steps can be configured to run only when certain criteria are met. This is typically done using the if keyword combined with the ${{ }} expression syntax.

Example of a conditional step based on output:
yaml - name: Conditional step if: ${{ steps.step_name.outputs.results > 3 }} run: echo 'the results are greater than 3!'

In this scenario, the workflow evaluates the output of a previous step. If the numeric value is greater than 3, the step executes.

Fail-Safe Mechanisms

Constants can also be used to force a workflow to terminate if specific conditions are not met, preventing the deployment of faulty code.

Example of a shutdown step:
yaml - name: Shut it down if: ${{ steps.step_name.outputs.results =< 3 }} run: | echo 'the results are less than or equal to 3! -- going to exit!' exit 1

By calling exit 1, the runner signals a failure, which stops the workflow and marks the job as failed.

Secret Management and User-Defined Variables

While GitHub provides a vast array of default constants, there are scenarios where sensitive data must be injected. This is handled via GitHub Secrets and user-defined variables.

GitHub Secrets

Secrets are encrypted variables that are not exposed in the workflow logs. A common use case is the GitHub Personal Access Token (PAT), which is a string that grants access to a user's GitHub account for performing API operations that exceed the default GITHUB_TOKEN permissions.

User-Set Variables

Beyond the default constants, users can define their own variables. There are two primary ways to interact with these:

  1. Defined in the YAML: Set under the env key at the workflow or job level.
  2. Defined in the GitHub UI: Set within the repository or environment settings.

To output these variables in a bash script, the expression syntax is used:
bash echo ${{ github.repository }}

Practical Workflow Implementation

To apply these constants in a real-world scenario, a developer typically follows a specific git-flow to test and deploy their configuration.

Configuration Workflow Example

To experiment with variables and secrets, the following process is recommended:

  1. Create a dedicated feature branch for environment testing:
    bash git checkout -b "env-var"

  2. Move the configuration file into the required directory structure:
    bash mv activity-1-sample-github-actions/exploring-var-and-secrets.yml .github/workflows/exploring-var-and-secrets.yml

  3. Commit and push the changes to trigger the GitHub Actions engine:
    bash git add .github/* git commit -m "exploring gha variables" git push --set-upstream origin env-var

  4. Initiate a pull request to trigger the pull_request event, which populates variables like GITHUB_BASE_REF and GITHUB_HEAD_REF.

Analysis of Variable Interaction and Impact

The interaction between the github context and the GITHUB_ environment variables creates a robust framework for automation. The primary technical reason for this duplication is the difference between the "Orchestration Layer" and the "Execution Layer."

The Orchestration Layer (handled by the GitHub Actions controller) uses the github context to decide whether a job should start or which step should be skipped. Because this happens before the runner is even provisioned, it cannot rely on shell environment variables.

The Execution Layer (the actual VM or container) uses the GITHUB_ environment variables. Once the shell is spawned, the operating system needs these values as standard environment variables to execute scripts.

The impact on the user is a seamless transition from high-level YAML logic to low-level shell execution. For example, a user can use github.ref in an if statement to decide whether to run a deployment step, and then use $GITHUB_REF inside a shell script to name a Docker image.

This system ensures that the workflow remains portable. Because the constants are provided by the platform, the same workflow file can be moved from one repository to another without needing to update the repository name, owner, or API URLs, as these are dynamically injected by the environment.

Sources

  1. GitHub Docs - Variables
  2. Hutch Data Science - GitHub Automation for Scientists
  3. GitHub Docs - Contexts

Related Posts