# Anatomy of a Workflow — GitHub Actions

Source: https://www.skillbyai.com/en/github-actions/i-anatomy

> on, permissions, jobs, steps.

## Read a workflow top to bottom

A workflow has a `name`, an `on` block listing triggers, optional top-level `permissions` and `concurrency`, and `jobs`. Each job has a `runs-on` runner label and a list of `steps`; a step either `uses` an action (with `with` inputs) or `run`s shell commands. Jobs run **in parallel** by default and each starts on a **fresh runner**, so files are not shared between jobs unless passed as artifacts or outputs.

## A complete CI workflow, linted

I checked this workflow with actionlint 1.7.12 (`actionlint -oneline .github/workflows/ci.yml`); the output and exit code are copied from that run. actionlint validates syntax, expressions, job dependencies and known actions offline; shellcheck was not installed, so shell scripts inside run: were not linted. The workflow was not executed on GitHub. The workflow tests on Node 20 and 22, cancels superseded runs, restricts the token to read access and uploads a build artifact; actionlint reports no problems.

```yaml
name: CI

on:
  push:
    branches: [main]
  pull_request:

permissions:
  contents: read

concurrency:
  group: ci-${{ github.ref }}
  cancel-in-progress: true

jobs:
  test:
    runs-on: ubuntu-latest
    timeout-minutes: 15
    strategy:
      fail-fast: false
      matrix:
        node: [20, 22]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}
          cache: npm
      - run: npm ci
      - run: npm test

  build:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci && npm run build
      - uses: actions/upload-artifact@v4
        with:
          name: dist
          path: dist/
```

Output:

```
(no problems found)
(exit code 0)
```

## One workflow per purpose

Separate CI, release and housekeeping workflows; small files are easier to review and to permission correctly.

**Quiz:** Do two jobs in the same workflow share files by default?

- [x] No, each job runs on a fresh runner; use artifacts or outputs to pass data
- [ ] Yes, always
- [ ] Only on Windows runners
- [ ] Only if they have the same name

*Answer:* No, each job runs on a fresh runner; use artifacts or outputs to pass data. Jobs are isolated.
