1.2 GitHub Actions Architecture & Core Mental Model

Key Takeaways

  • GitHub Actions operates on a four-tier hierarchical execution graph: Workflows contain one or more Jobs, Jobs run on specific Runners and contain sequential Steps, and Steps execute shell commands or reusable Actions.
  • Workflows are event-driven, triggered by repository webhook events, POSIX schedules, or manual/API dispatches, which inject rich JSON event payloads into the `${{ github.event }}` context.
  • Jobs execute in parallel by default on isolated, ephemeral runner virtual machines or containers, sharing no filesystem state unless explicitly coordinated via `needs` dependencies and artifact transfers.
  • Steps within the same job execute sequentially on a single runner instance, sharing the filesystem, working directory (`$GITHUB_WORKSPACE`), and environment variables written to `$GITHUB_ENV`.
  • Runners communicate with GitHub's backend strictly over outbound HTTPS (TCP port 443) via long polling or WebSockets, requiring zero inbound firewall ports to be exposed.
Last updated: August 2026

GitHub Actions Architecture & Core Mental Model

To pass the GH-200 exam and architect resilient CI/CD pipelines, you must understand the underlying execution engine of GitHub Actions. GitHub Actions is not simply a task runner; it is a distributed, event-driven orchestration system built on a strictly enforced component hierarchy and an asynchronous message-queue architecture.


1. The Four-Tier Component Hierarchy

Every automated pipeline in GitHub Actions conforms to a four-tier hierarchy: Workflow, Job, Step, and Action/Command.

+-----------------------------------------------------------------------------+
|                   GITHUB ACTIONS COMPONENT HIERARCHY                        |
|                                                                             |
|   +---------------------------------------------------------------------+   |
|   | WORKFLOW (.github/workflows/*.yml)                                  |   |
|   | Top-level automated process triggered by events                     |   |
|   |                                                                     |   |
|   |   +--------------------------+     +----------------------------+   |   |
|   |   | JOB 1: 'build'           |     | JOB 2: 'test' (needs: build)|   |   |
|   |   | Runs on Runner VM A      |     | Runs on Runner VM B        |   |   |
|   |   |                          |     |                            |   |   |
|   |   |  [Step 1: Checkout]      |     |  [Step 1: Download Artifact|   |   |
|   |   |         |                |     |         |                  |   |   |
|   |   |  [Step 2: Setup Node]    |     |  [Step 2: Run Tests]       |   |   |
|   |   |         |                |     |         |                  |   |   |
|   |   |  [Step 3: Compile App]   |     |  [Step 3: Post Summary]    |   |   |
|   |   +--------------------------+     +----------------------------+   |   |
|   +---------------------------------------------------------------------+   |
+-----------------------------------------------------------------------------+

1. Workflow (The Orchestration Root)

  • A workflow is an automated, configurable process defined by a YAML file located strictly in the repository's .github/workflows/ directory.
  • A repository can contain multiple workflows (e.g., ci.yml, release.yml, security-scan.yml).
  • Each workflow defines its own triggers (on:), global environment variables, concurrency limits, defaults, permissions, and set of jobs.

2. Job (The Unit of Distributed Execution)

  • A job is a set of steps that execute on a single designated Runner (virtual machine or container).
  • Parallelism by Default: By default, multiple jobs defined inside the same workflow execute concurrently in parallel as soon as runner capacity becomes available.
  • Sequential Execution via needs: To enforce sequential execution or construct a Directed Acyclic Graph (DAG), you must declare dependencies explicitly using the needs: keyword (e.g., needs: [build, lint]).
  • Isolated Environments: Each job runs on a separate, fresh runner instance with its own isolated virtual machine or container environment. Filesystem modifications in Job A are completely inaccessible to Job B unless shared via artifact uploads or external storage.

3. Step (The Sequential Task Unit)

  • A step is an individual task that runs sequentially inside the job's assigned runner environment.
  • A step can be either:
    1. An Action (reusable unit invoked with uses: actions/checkout@v4).
    2. A Shell Command (executable script run with run: npm test).
  • Shared Context: All steps within a single job share the same runner filesystem, the same working directory ($GITHUB_WORKSPACE), and environment variables exported to $GITHUB_ENV.
  • Failure Propagation: If a step fails (returns a non-zero exit code), GitHub Actions immediately halts execution of subsequent steps in that job by default, unless overridden by continue-on-error: true or conditional status functions like if: always().

4. Action (The Smallest Reusable Building Block)

  • An action is a reusable, standalone application component packaged for execution inside a workflow step.
  • Actions can be authored as Composite Actions (combining multiple run steps), JavaScript Actions (Node.js runtime), or Docker Container Actions (Linux container image).

2. Event-Driven Architecture & Webhook Payloads

GitHub Actions is fundamentally event-driven. Execution is initiated when specific activities occur within GitHub, on a schedule, or via an external API call.

+-----------------------------------------------------------------------------+
|                        EVENT INGESTION & DISPATCH                           |
|                                                                             |
|   [REPOSITORY ACTIVITY]       [TIME SCHEDULE]       [EXTERNAL DISPATCH]     |
|   - Git Push                  - POSIX Cron          - REST API Webhook      |
|   - Pull Request Opened       - Daily / Hourly      - repository_dispatch   |
|   - Issue Comment                                                           |
|             \                        |                       /              |
|              \                       |                      /               |
|               v                      v                     v                |
|       +-------------------------------------------------------------+       |
|       |             GITHUB EVENT INGESTION SERVICE                  |       |
|       | - Validates webhook payload & filters (branch/tag/path)     |       |
|       | - Injects payload into `${{ github.event.* }}` context      |       |
|       | - Queues workflow run execution graph                        |       |
|       +-------------------------------------------------------------+       |
+-----------------------------------------------------------------------------+

When an event occurs:

  1. GitHub's internal webhook system creates a structured JSON payload describing the actor, repository, commit SHA, branch reference, pull request metadata, or issue details.
  2. GitHub parses all workflow files in .github/workflows/ whose on: trigger declarations match the event and satisfy any configured branch, tag, or path filters.
  3. The complete event JSON payload is injected into the workflow's ${{ github.event }} context, allowing steps and conditional expressions (if:) to inspect payload attributes (e.g., ${{ github.event.pull_request.base.ref }}).

3. Runner Architecture & Outbound Network Topology

A Runner is the compute application that checks out your code, processes the steps defined in a job, reports status updates, and streams execution logs back to GitHub.

+-----------------------------------------------------------------------------+
|                    RUNNER OUTBOUND COMMUNICATION MODEL                      |
|                                                                             |
|   [ENTERPRISE DATA CENTER / CLOUD VPC]              [GITHUB ENTERPRISE]     |
|   +---------------------------------------+         +-------------------+   |
|   | Self-Hosted Runner Machine            |         | GitHub Service    |   |
|   |                                       |         | Backend           |   |
|   |   +-------------------------------+   |         |                   |   |
|   |   | `actions-runner` Daemon       |   |         |                   |   |
|   |   +-------------------------------+   |         |                   |   |
|   |                   |                   |         |                   |   |
|   |                   | Outbound HTTPS    |         |                   |   |
|   |                   | (TCP Port 443)    |         |                   |   |
|   |                   | Long-Poll/WSS     |         |                   |   |
|   |                   +---------------------------->| Job Message Queue |   |
|   |                                       |         | & Log Ingestion   |   |
|   | [NO INBOUND PORTS OPENED (Port 22/80 X|         |                   |   |
|   +---------------------------------------+         +-------------------+   |
+-----------------------------------------------------------------------------+

The Outbound-Only Communication Principle

A critical architectural concept frequently tested on the GH-200 exam is the runner networking model:

  • Runners communicate with GitHub Enterprise Cloud or GitHub Enterprise Server exclusively via outbound HTTPS connections on TCP port 443.
  • The runner agent utilizes HTTP long-polling and secure WebSockets (wss://) to poll GitHub's job dispatch queue.
  • No Inbound Ingress Required: Network administrators never need to open inbound firewall ports, configure public IP addresses, or create inbound port-forwarding rules to enable self-hosted runners. This architecture allows runners to operate securely inside restricted private enterprise subnets and air-gapped VPCs.

4. Runner Filesystem & Workspace Topography

When a job executes on a runner, GitHub Actions establishes a standardized directory structure. Understanding these environment variables and directory paths is essential for debugging and workflow authoring.

Environment VariableDirectory Purpose & StructureLifecycle & Scope
$GITHUB_WORKSPACEThe default working directory where actions/checkout clones your repository (e.g., /home/runner/work/repo-name/repo-name).Preserved across all steps within the same job; wiped between jobs on hosted runners.
$RUNNER_TEMPA temporary scratch directory for transient files, scripts, and downloaded packages (e.g., /home/runner/work/_temp).Available to all steps in the job; automatically deleted during job post-cleanup.
$RUNNER_TOOL_CACHEDirectory containing pre-installed software toolchains (Node.js, Python, Java, Go, Ruby).Read-only cache on hosted runners; managed via setup actions (e.g., actions/setup-node).
$GITHUB_ENVPath to a local file used to export environment variables to subsequent steps (echo "VAR=value" >> $GITHUB_ENV).Processed by the runner agent after each step completes to update the step environment.
$GITHUB_OUTPUTPath to a local file used to export step outputs (echo "output_key=value" >> $GITHUB_OUTPUT).Persisted in the step execution context for consumption via ${{ steps.<id>.outputs.* }}.
$GITHUB_PATHPath to a local file used to prepend directories to the system $PATH (echo "/custom/bin" >> $GITHUB_PATH).Automatically updates the search path for all subsequent steps in the job.

5. State Management: Job Isolation vs. Step Shared State

The fundamental boundary rule in GitHub Actions is the distinction between Step Shared Context and Job Isolation.

+-----------------------------------------------------------------------------+
|                  SHARED STEP CONTEXT VS. JOB ISOLATION                      |
|                                                                             |
|   +=====================================================================+   |
|   | JOB A (Runner 1 VM)                                                 |   |
|   |   Step 1: Creates file -> `$GITHUB_WORKSPACE/dist/app.js`           |   |
|   |   Step 2: Appends to `$GITHUB_ENV` -> `BUILD_NUM=42`                |   |
|   |   Step 3: Reads `$BUILD_NUM` and accesses `./dist/app.js` (SUCCESS) |   |
|   +=====================================================================+   |
|                                     |                                       |
|                    ISOLATION BOUNDARY (Separate VMs)                        |
|               (Cannot read memory, env, or disk directly)                   |
|                                     |                                       |
|                                     v                                       |
|   +=====================================================================+   |
|   | JOB B (Runner 2 VM - `needs: [Job A]`)                              |   |
|   |   Step 1: Looks for `./dist/app.js` (FAILS unless uploaded/downloaded)  |
|   |   Step 2: Looks for `$BUILD_NUM` (FAILS unless passed via job outputs)  |
|   +=====================================================================+   |
+-----------------------------------------------------------------------------+

Comparison of Workflow Components

DimensionWorkflowJobStepAction
ScopeRepository / GlobalSingle Runner InstanceSingle Command / ActionReusable Subtask
Execution ModeTriggered by eventsParallel by default; sequential with needsStrictly SequentialSynchronous within step
Filesystem StateN/A (Config file)Isolated per VM / ContainerShared across steps in jobShared within job workspace
Environment StateDeclared in env: blockDeclared in job env:Updated via $GITHUB_ENVScoped to action inputs/env
Syntax TagTop-level YAML rootjobs.<job_id>jobs.<job_id>.steps[]uses: <owner>/<repo>@<ref>

6. Execution Lifecycle Diagram

The following sequence illustrates how a repository event transitions from an initial Git action to distributed runner execution and final status reporting.

Loading diagram...
GitHub Actions Workflow-to-Runner Execution Lifecycle
Test Your Knowledge

A network security administrator is configuring egress filtering rules on an enterprise firewall protecting a subnet of self-hosted GitHub Actions runners. Which communication requirement represents the correct architectural model for runner connectivity to GitHub Enterprise Cloud?

A
B
C
D
Test Your Knowledge

A workflow defines two jobs: build-app and publish-app. The build-app job compiles a binary at $GITHUB_WORKSPACE/bin/release. The publish-app job defines needs: build-app and immediately attempts to run ./bin/release --upload. What is the result when this workflow executes on standard GitHub-hosted runners?

A
B
C
D
Test Your Knowledge

Within a single workflow job, Step 1 creates a local configuration file at $GITHUB_WORKSPACE/config.json and Step 2 executes echo "STAGE=production" >> $GITHUB_ENV. What is the state of the runner environment when Step 3 executes inside the same job?

A
B
C
D