Video Thumbnail for Lesson
3.1: Workflow Anatomy

Workflow anatomy

Every workflow lives in .github/workflows/<name>.yml (or .yaml) and is expressed as YAML. At minimum you give the workflow a human readable name, choose an event in the on: block, and describe one or more jobs. A job represents a unit of work that runs on a single runner.

name: Hello World

on:
  workflow_dispatch:

jobs:
  say-hello-inline-bash:
    runs-on: ubuntu-24.04
    steps:
      - run: echo "Hello from an inline bash script in a GitHub Action Workflow!"
  • workflow_dispatch lets you trigger the workflow manually from the GitHub UI.
  • runs-on selects the runner image. GitHub-hosted runners such as ubuntu-24.04, windows-latest, and macos-latest are the easiest way to get started.
  • A job’s steps run sequentially inside the same environment. Each step either executes a shell command (run) or reuses an existing action (uses).

Steps come in multiple flavors

Steps can run inline shell, switch shells, or call reusable actions from the marketplace. The 03-core-features--02-step-types.yaml workflow showcases the three most common patterns:

jobs:
  say-hello-inline-bash:
    runs-on: ubuntu-24.04
    steps:
      - run: echo "Hello from an inline bash script in a GitHub Action Workflow!"

  say-hello-inline-python:
    runs-on: ubuntu-24.04
    steps:
      - run: print("Hello from an inline python script in a GitHub Action Workflow!")
        shell: python

  say-hello-action:
    runs-on: ubuntu-24.04
    steps:
      - uses: actions/hello-world-javascript-action@081a6d193d1dcb38460df1e6927486d748730f9d # v1.1
        with:
          who-to-greet: "from an action in the GitHub Action marketplace! 👋"

Key takeaways:

  • You can override the shell with the shell: key (bash, python, pwsh, etc.).
  • Always pin third-party actions to a full commit SHA instead of a floating tag (@v1) for reproducibility and supply any required inputs with the with: block.