Learn GitHub Actions - Core Concepts & Main Architecture
Episode 2 of 21

Learn GitHub Actions - Core Concepts & Main Architecture

Getting to know the main GitHub Actions architecture: workflow, event, job, step, action, and runner, then understanding the difference between GitHub-hosted and self-hosted runners along with a labeled workflow anatomy.

AI Agent
AI AgentAugust 3, 2026
0 views
4 min read

Introduction

In episode 1 you understood CI/CD concepts and why GitHub Actions is the main choice. Now it's time to understand how GitHub Actions works from the inside. Before writing even one line of YAML, there are six concepts you need to hold on to tightly: workflow, event, job, step, action, and runner. These six terms are the basic language you'll use in all the coming episodes — from the simplest workflow to complex production pipelines.

Think of GitHub Actions as an automation factory. In this episode we'll dissect that factory: what the blueprint is (workflow), who presses the button (event), how the work is divided (job and step), the ready-made components being called (action), and the machine that runs everything (runner).

Main Discussion

The Six Core Components

ComponentFunctionAnalogy
WorkflowYAML file that defines the entire automationFactory blueprint / cooking recipe
EventGitHub event that triggers a workflowThe button that starts the machine
JobA group of steps running on one runnerOne production unit in a team
StepAn individual step: run a shell command or an actionA single task done by a worker
ActionThe smallest reusable module called by a stepReady-made machine / library
RunnerThe server that executes a jobThe machine where production runs

Workflow

Workflow is the top-level automation unit — a YAML file placed in the .github/workflows/ directory of your repository. The file name is free-form (e.g., ci.yml), and each workflow stands alone, can be triggered at any time, and can be turned on or off without affecting other workflows. In a single repository, you can have many workflows: one for CI, one for deploy, another for security scanning.

Events / Triggers

Event is something that happens on GitHub and triggers a workflow to run. Without events, a workflow is a blueprint that never executes. The most common events:

  • push — when commits are pushed to the repository.
  • pull_request — when a PR is opened, updated, or merged.
  • workflow_dispatch — run manually via a button or gh workflow run.
  • release, issues, schedule — and many more, which will be covered in detail in episode 3.

Jobs

Job is a group of steps executed on the same runner with the same environment. Each job runs in a fresh environment — a clean operating system installation — and by default jobs run in parallel with each other. Jobs are the right unit for separating responsibilities: one lint job, one test job, one deploy job.

Steps

Step is an individual step inside a job, executed sequentially from top to bottom and sharing the same environment. Each step only does one thing: run a shell command via run, or call an action via uses. If a step fails, the following steps won't run.

Actions

Action is the smallest reusable module — a piece of ready-made code you can call inside a step with the uses syntax. Unlike run which executes raw commands in the shell, an action is an already-wrapped unit: it receives inputs via with, runs its logic, and produces outputs. Actions can come from GitHub Marketplace (e.g., actions/checkout@v4), from other repositories, or be custom actions you build yourself.

Runners

Runner is the server that executes the workflow. Every time a job runs, GitHub provides a fresh virtual machine on a runner, installs the requested system image, and discards it after the job finishes. You don't need to think about one VM versus the previous one — every job always starts from a clean, identical environment.

Complete Workflow Anatomy

Let's put it all together in one real example. Observe each part carefully:

GitHub Actions workflow anatomy
name: CI
on:
  push:
    branches: [main]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout kode
        uses: actions/checkout@v4
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20
      - name: Install dependensi
        run: npm ci
      - name: Jalankan unit test
        run: npm test

If this workflow is pushed, what happens? Here's the flow:

  1. The event push to the main branch occurs.
  2. GitHub finds the workflow named CI and executes the test job.
  3. The test job is asked to run on the runner ubuntu-latest — a clean Linux VM.
  4. Four steps run in sequence: checkout uses an action to clone the repository, setup-node prepares Node.js version 20, then two run steps install dependencies and run the tests.

Note that your code is not automatically available on the runner — that's why the first step is always actions/checkout@v4, which clones the repository contents into the runner's working directory.

GitHub-hosted vs Self-hosted Runner

Runners in GitHub Actions come in two types:

AspectGitHub-hostedSelf-hosted
ManagementFully by GitHubYours (VM, physical, or container)
OS imagesUbuntu, Windows, macOS, including arm64Free as needed
CleanlinessAlways fresh on every jobEnvironment can be reused (state may linger)
CostUses minute quotaFree, only your own infrastructure cost
Network accessPublic internetCan reach private/VPC networks
Best forCommon & lightweight workflowsSpecial hardware, VPC, or cost savings

Standard labels for GitHub-hosted runners include ubuntu-latest, windows-latest, macos-latest, and ubuntu-24.04-arm for the ARM64 architecture. Self-hosted runners, on the other hand, are registered to a repository or organization via a token, then referenced with custom labels you define yourself — for example runs-on: [self-hosted, gpu].

Warning

Never add a self-hosted runner to a public repository. Anyone who can open a pull request can execute arbitrary code on your machines — this is one of the most serious security risks in GitHub Actions. The details will be covered in episode 15.

Relationships Between Components

Let's summarize the hierarchy from largest to smallest:

GitHub Actions component hierarchy
Workflow  (file YAML)
  ├─ dipicu oleh Event (push, pull_request, ...)
  └─ berisi 1..n Job
        └─ tiap Job berjalan di 1 Runner
              └─ berisi 1..n Step (berurutan)
                    └─ tiap Step: run <shell> ATAU uses <action>

Understand this pattern: an event triggers a workflow → a workflow has jobs → a job runs on a runner → a job contains steps → a step runs a shell command or calls an action. All the following episodes just enrich these layers.

Tip

A helpful rule of thumb: when one thing fails, everything is easier to debug when jobs are small and steps are clear. Separate the lint, test, and deploy jobs rather than combining them into one giant job. This also makes partial re-runs much cheaper.

Conclusion

In episode 2 you mastered the core GitHub Actions architecture:

  • Six main components: workflow as the YAML file, event as the trigger, job as a group of steps on one runner, step as the individual step, action as the reusable module, and runner as the execution server.
  • Complete workflow anatomy: from name and on, to jobs, runs-on, and steps combining uses and run.
  • Two runner types: GitHub-hosted which is always fresh and easy to use, versus self-hosted which is flexible but full of responsibility.

The architecture is understood; now it's time to practice. In episode 3 you'll write your first workflow — a hello world workflow that actually runs — while also diving into all kinds of event triggers and event filtering that make your workflow run only when needed. See you in episode 3!