The orchestration of modern continuous integration and continuous delivery (CI/CD) pipelines relies heavily on the ability of a workflow to interact with its execution environment. Within the GitHub Actions ecosystem, this interaction is facilitated through a sophisticated system of variables. These variables serve as the connective tissue between the GitHub platform, the runner operating system, and the specific scripts or actions being executed. For a developer to construct a workflow, shell script, or build job of any significant merit, it is imperative to move beyond basic configurations and leverage the full spectrum of available environment variables. These variables provide critical metadata about the trigger event, the state of the repository, the identity of the actor initiating the process, and the specific characteristics of the host runner.
The architecture of GitHub Actions variables is divided into several distinct categories: default environment variables provided by GitHub, runner-specific system variables, and user-defined configuration variables. While the standard documentation highlights a core set of variables prefixed with GITHUB_, there is a much broader landscape of variables available depending on the operating system—such as Ubuntu, macOS, or Windows. Each containerized environment where a build runs offers a comprehensive suite of variables that can be accessed via the shell. This depth of information allows for highly dynamic workflows that can adapt their behavior based on the environment they are inhabiting, such as adjusting file paths for different operating systems or targeting specific API endpoints based on the workflow's context.
Default GitHub Actions Environment Variables
GitHub provides a set of default environment variables that are automatically injected into every step of a workflow. These variables are essential for identifying the current state of the execution and the context of the event that triggered the run. There are 18 primary default environment variables available to any shell script or workflow, regardless of the runner's operating system.
The following table details the primary default environment variables and their specific functions:
| Variable | Description |
|---|---|
| CI | Always set to true. This allows scripts to detect if they are running in a CI environment versus a local developer machine. |
| GITHUB_ACTION | The name of the action currently running, or the ID of a step. For actions, it follows the format repo-owner_name-of-action-repo. If the step runs a script without an ID, GitHub uses __run. If a script or action is used multiple times in one job, a sequence number is added (e.g., __run_2 or actionscheckout2). |
| GITHUBACTIONPATH | The filesystem path where the action is located. This is exclusively supported in composite actions and is critical for changing directories to access other files within the action's repository, such as /home/runner/work/_actions/repo-owner/name-of-action-repo/v1. |
| GITHUBACTIONREPOSITORY | The owner and repository name of the action being executed, such as actions/checkout. |
| GITHUB_ACTIONS | Always set to true when GitHub Actions is executing the workflow. This provides a secondary method to differentiate between local tests and GitHub-hosted execution. |
| GITHUB_ACTOR | The username of the person or the app that initiated the workflow run, for example, octocat. |
| GITHUB_WORKFLOW | The name of the workflow. |
| GITHUBRUNID | A unique identifier for the specific run. |
| GITHUBRUNNUMBER | A unique number for the specific run within a workflow. |
| GITHUB_REPOSITORY | The owner and repository name. |
| GITHUBEVENTNAME | The name of the event that triggered the workflow. |
| GITHUBEVENTPATH | The path to the file containing the full event payload. |
| GITHUB_WORKSPACE | The path to the directory where the checkout action puts the repository content. |
| GITHUB_SHA | The commit SHA that triggered the workflow. |
| GITHUB_REF | The branch or tag ref that triggered the workflow. |
| GITHUBHEADREF | The target branch for pull request workflows. |
| GITHUBBASEREF | The source branch for pull request workflows. |
| GITHUBSERVERURL | The URL of the GitHub server. |
| GITHUBAPIURL | The URL used to make REST API requests to GitHub. |
| GITHUBGRAPHQLURL | The URL used to make GraphQL API requests to GitHub. |
The impact of these variables on the developer experience is profound. For instance, using GITHUB_WORKSPACE ensures that the workflow remains portable across different runner environments by avoiding hardcoded paths. This is a critical best practice; GitHub strongly recommends using these variables to access the filesystem rather than relying on absolute paths, which may vary between Ubuntu and Windows runners.
Contextual Mapping and the Env Context
A critical distinction exists between environment variables and the env context. Default environment variables set by GitHub are available to every step in a workflow, but because they are managed by the platform and not defined within the YAML configuration, they are not accessible through the ${{ env }} context.
To bridge this gap, GitHub provides corresponding context properties for most default variables. The relationship is usually a direct mapping of the variable name to a property in the github context.
- The environment variable
GITHUB_REFcorresponds to the context property${{ github.ref }}. - This allows developers to use the variable in a shell script as
$GITHUB_REFand in a workflow expression as${{ github.ref }}.
There are strict rules regarding the modification of these variables. Users cannot overwrite the values of default environment variables that begin with GITHUB_* or RUNNER_*. However, the CI variable can currently be overwritten, though GitHub does not guarantee that this capability will persist in future iterations of the platform.
Runner-Specific Environment Variables
While the 18 default variables are universal, the actual environment available to a workflow is much larger. Each operating system image provides its own set of system-level variables. These vary significantly by distribution.
For example, a build running on the ubuntu-latest image provides over 60 additional environment variables beyond the default GitHub set. Similarly, the macos-latest image contains a different set of variables, which may be slightly more or fewer than those found on Ubuntu.
The windows-latest environment is particularly expansive, offering approximately 120 environment variables. These include critical system paths and tool configurations, such as:
ALLUSERSPROFILE: Set toC:\ProgramData.ANDROID_HOME: Set toC:\Program Files (x86)\Android\android-sdk.ANDROID_NDK_HOME: Set toC:\Program Files (x86)\Android\android-sdk.PATH: Available onwindows-latestand used to locate executable binaries.
The consequence of this variability is that developers must be aware of the specific runner they are targeting. A script that relies on a specific system variable present in ubuntu-latest may fail when migrated to windows-latest or macos-latest.
Variable Inspection and Discovery
Because the full list of variables changes between different runner images and versions, developers can use a discovery workflow to inspect the actual environment they are operating in. By invoking the env command in a shell, the container will print all available environment variables to the console log.
To implement this discovery process, a developer can use the following workflow structure:
- Create a YAML file configured to trigger on a
pushto themainormasterbranch. - Define three separate jobs, each targeting a different runner:
ubuntu-latest,windows-latest, andmacos-latest. - In each job, execute a step that runs the
envcommand. - Execute the workflow and inspect the job status window to view the complete output.
The following code snippet demonstrates this implementation:
```yaml
name: Publish GitHub Actions Artifacts Example
on:
push:
branches: [ main ]
jobs:
github-actions-environment-variables-ubuntu:
runs-on: ubuntu-latest
steps:
- name: Ubuntu GitHub Actions environment variables List
run: env
github-actions-environment-variables-windows:
runs-on: windows-latest
steps:
- name: List of the GitHub Actions environment variables on Windows
run: env
github-actions-environment-variables-macos:
runs-on: macos-latest
steps:
- name: MacOs List of GitHub Actions environment variables
run: env
```
This approach allows a developer to move from theoretical documentation to empirical evidence of what is available in their specific build environment.
State Management and Inter-Job Variable Sharing
Historically, GitHub Actions lacked a native mechanism to share variables across different jobs within the same workflow. This gap led to the creation of third-party solutions, such as the store-variables action created in 2021. This action allowed developers to store variables in a global store and read them in later jobs, automatically adding the read variables to the ${{ env }} context for subsequent steps.
However, GitHub has since introduced native support for sharing data between jobs. This is achieved through the use of step outputs and job outputs. Instead of relying on external store actions, developers can now write key/value pairs directly to the $GITHUB_OUTPUT environment file.
The process of sharing data natively involves:
- Writing a value to the
$GITHUB_OUTPUTfile within a step. - Defining that value as an output of the job.
- Referencing that output in a subsequent job using the
needskeyword and theneedscontext.
This evolution reduces the dependency on third-party marketplace actions and improves the security and reliability of the data pipeline within a workflow.
Conclusion
The variable system in GitHub Actions is a multi-layered architecture designed to provide maximum flexibility across diverse computing environments. By combining a core set of 18 universal GITHUB_* variables with extensive, OS-specific system variables, GitHub enables the creation of highly adaptive CI/CD pipelines. The ability to differentiate between a local environment and a CI environment using the CI variable, combined with the use of GITHUB_WORKSPACE for filesystem abstraction, allows developers to write portable and robust automation scripts.
The shift from third-party variable storage to native $GITHUB_OUTPUT mechanisms signifies a move toward a more integrated and standardized data flow. For the technical practitioner, the most effective way to master this environment is to treat the runner as a transparent box, using the env command to audit the available variables on ubuntu-latest, windows-latest, and macos-latest. This empirical approach ensures that workflows are optimized for the specific characteristics of the underlying container, ultimately leading to more stable and predictable software delivery cycles.