GitHub Actions Workflow File Basics
Every GitHub Actions workflow lives in a YAML file. YAML is a simple text format that uses indentation to organize data — similar to how a bulleted outline works on paper. This topic walks you through the structure of a workflow file so you can read and write one confidently.
Where the File Lives
GitHub Actions only recognizes workflow files stored in a specific folder path inside your repository:
your-repo/
└── .github/
└── workflows/
└── ci.yml
The folder name starts with a dot (.github), which marks it as a configuration folder. The file can have any name, but it must end in .yml or .yaml.
The Skeleton of Every Workflow File
Every workflow file shares the same top-level structure:
name: My First Workflow
on:
push:
branches:
- main
jobs:
say-hello:
runs-on: ubuntu-latest
steps:
- name: Print a message
run: echo "Hello, GitHub Actions!"
This small file already contains all five core concepts from the previous topic. Read through each section below to understand what every part does.
The name Field
The name field gives your workflow a human-readable title. GitHub displays this name in the Actions tab of your repository.
name: Build and Test
This field is optional but always worth adding. Clear names make it easy to spot which workflow is running when you have several active at the same time.
The on Field — Defining the Trigger
The on field tells GitHub which event starts this workflow. This field is required.
on:
push:
branches:
- main
The example above says: "Start this workflow whenever someone pushes code to the main branch." You can trigger on multiple events at once:
on:
push:
branches:
- main
pull_request:
branches:
- main
Now the workflow runs on both pushes and pull requests targeting the main branch.
The jobs Field — Defining the Work
The jobs field contains one or more named jobs. Each job has its own indented block.
jobs:
build:
runs-on: ubuntu-latest
steps:
- run: echo "Building the app"
test:
runs-on: ubuntu-latest
steps:
- run: echo "Running tests"
The runs-on Key
Every job must specify which operating system it runs on. runs-on: ubuntu-latest is the most common choice. Other valid values include windows-latest and macos-latest.
The steps Key
Steps live inside a job and run in order from top to bottom. Each step can have a name (optional label), a run key (for shell commands), or a uses key (for pre-built actions).
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Install dependencies
run: npm install
- name: Run tests
run: npm test
YAML Indentation Rules
YAML uses spaces (not tabs) for indentation. Misaligned spaces cause the entire workflow to fail. Follow these rules to stay safe:
- Use two spaces per indent level
- Never mix tabs and spaces
- Items under the same parent must align exactly
jobs: ← level 0
build: ← level 1 (2 spaces)
runs-on: ... ← level 2 (4 spaces)
steps: ← level 2 (4 spaces)
- name: ... ← level 3 (6 spaces)
run: ... ← level 4 (8 spaces)
A Complete Annotated Example
name: CI Pipeline # Workflow display name
on: # Trigger section
push:
branches:
- main
jobs: # All jobs go here
build-and-test: # Job name (you choose this)
runs-on: ubuntu-latest # Runner OS
steps: # Steps run top to bottom
- name: Get the code
uses: actions/checkout@v4 # Downloads repo onto runner
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install packages
run: npm install
- name: Run all tests
run: npm test
Validating Your Workflow File
GitHub validates your workflow file automatically when you push it. If the YAML structure is wrong, GitHub shows an error in the Actions tab. You can also check your YAML before pushing using a free online YAML validator or the GitHub Actions extension for VS Code, which highlights errors as you type.
Key Rules to Remember
- The file must be inside
.github/workflows/ - The
onandjobsfields are required - Use two spaces for each indentation level
- Each job needs a
runs-onvalue - Each step uses either
runoruses, not both
