The github context is your primary window into the event that triggered your workflow, providing a rich source of metadata about the commit, repository, and actor.

Let’s see the github context in action. Imagine a workflow that runs on every push to the main branch. We want to log the commit SHA, the author’s name, and the repository URL.

name: GitHub Context Demo

on:
  push:
    branches:
      - main

jobs:
  show_github_context:
    runs-on: ubuntu-latest
    steps:
      - name: Display GitHub context variables
        run: |

          echo "Commit SHA: ${{ github.sha }}"


          echo "Author Name: ${{ github.actor }}"


          echo "Repository URL: ${{ github.repository_url }}"


          echo "Event Name: ${{ github.event_name }}"


          echo "Ref: ${{ github.ref }}"

When this workflow runs after a push to main, the output in the job logs will look something like this:

Commit SHA: a1b2c3d4e5f678901234567890abcdef12345678
Author Name: your-github-username
Repository URL: https://github.com/your-github-username/your-repo-name
Event Name: push
Ref: refs/heads/main

The env context provides access to environment variables. This includes variables defined in your workflow file, variables set by the runner, and variables you might have configured at the repository or organization level.

Here’s how you can use env to access a custom environment variable set in your workflow:

name: Env Context Demo

on: push

jobs:
  show_env_context:
    runs-on: ubuntu-latest
    env:
      MY_CUSTOM_VAR: "This is a custom value"
    steps:
      - name: Display environment variables
        run: |

          echo "My Custom Variable: ${{ env.MY_CUSTOM_VAR }}"


          echo "Runner OS: ${{ env.RUNNER_OS }}"


          echo "Runner Temp Directory: ${{ env.RUNNER_TEMP }}"

The output would show:

My Custom Variable: This is a custom value
Runner OS: Linux
Runner Temp Directory: /home/runner/work/_temp

The secrets context is where sensitive information, like API tokens or passwords, is stored. These are never exposed directly in logs and are only available to jobs that explicitly declare a need for them.

Consider a workflow that needs to authenticate with a third-party service using an API key stored as a GitHub secret.

name: Secrets Context Demo

on: push

jobs:
  use_secret:
    runs-on: ubuntu-latest
    steps:
      - name: Use GitHub Secret
        run: |
          echo "Attempting to use API Key..."
          # In a real scenario, you'd pass this to a tool or script
          # For demonstration, we'll just echo a masked version if available

          if [ -n "${{ secrets.MY_API_KEY }}" ]; then

            echo "API Key is available (masked in logs)."
          else
            echo "MY_API_KEY secret is not set."
          fi

If you have a secret named MY_API_KEY configured in your repository’s settings, the output will indicate its presence, but the actual value will be masked in the logs.

Attempting to use API Key...
API Key is available (masked in logs).

The github context is populated based on the webhook event that triggers the workflow. For example, if a pull_request event triggers your workflow, github.event.pull_request.number will give you the PR number. If it’s a push event, github.event.head_commit.id will give you the commit SHA. This dynamic population means you need to be aware of the event type to access the correct nested properties within github.event.

The env context allows for hierarchical variable definition. Variables defined at the job level (as shown in the Env Context Demo) override variables defined at the workflow level, which in turn override repository-level, and then organization-level environment variables. This cascading behavior is crucial for managing configurations across different scopes.

When you access a secret, GitHub uses a special masking mechanism. If the secret value is printed directly to standard output or standard error, GitHub will replace it with *** to prevent accidental exposure. This masking works for exact matches of the secret value. If you manipulate the secret (e.g., echo "My token: ${{ secrets.MY_API_KEY }}" | cut -d ':' -f 2), the masked value might still appear. The safest way is to pass secrets directly as environment variables to your commands or tools that expect them.

The github context offers a wealth of information beyond just sha and actor. You can access details about the repository owner (github.repository_owner), the base and head branches for pull requests (github.base_ref, github.head_ref), and much more, all depending on the triggering event. It’s worth exploring the full schema documentation to understand the breadth of data available for each event type.

The env context is not just for static values. You can dynamically set environment variables within a job using the run command and then access them in subsequent steps within the same job. For example, a script could generate a temporary token and echo "::set-env name=MY_TEMP_TOKEN::$(generate_token)" (though set-env is deprecated; echo "::set-output name=MY_TEMP_TOKEN::$(generate_token)" is the modern equivalent for outputs, which can then be used in subsequent steps via steps.<step_id>.outputs.MY_TEMP_TOKEN).

The secrets context is crucial for security, but it’s important to remember that secrets are only available to jobs that are allowed to access them. If a workflow runs on a pull_request from a fork, secrets are not available by default for security reasons. You can enable them for specific workflows via repository settings.

Understanding how github, env, and secrets contexts interact is key to building robust and secure GitHub Actions workflows. You’ll often combine them, for instance, using a github context variable to determine which secret to use based on the branch or event.

The next step is understanding how to use these contexts to control workflow logic, perhaps by conditionally running jobs or steps based on the event type or the value of a secret.

Want structured learning?

Take the full Github-actions course →