Free — no signup required

Workflow Syntax Anatomy

2 min read

The Structure of a Workflow File

A GitHub Actions workflow is a YAML file placed in the .github/workflows/ directory of your repository. GitHub automatically discovers and registers every .yml or .yaml file in that directory. You can have multiple workflow files — one for CI, one for deployments, one for scheduled maintenance tasks.

A production-grade workflow has four major sections. Triggers (the on: block) declare which Git events start the workflow — for example, pushes to main and new or updated pull requests. Permissions scope what the auto-generated GITHUB_TOKEN is allowed to do for this run, following least privilege — read-only on repo contents, write access only where needed (like posting PR comments). Concurrency controls how overlapping runs of the same workflow on the same ref are handled — typically grouped by workflow and branch, with newer runs cancelling older in-flight ones. Jobs are the units of work themselves, each specifying a runner environment and a sequence of steps — some of which invoke reusable "Actions" from the Marketplace or your own repo (like checking out the code or installing a language runtime with built-in dependency caching), and some of which are plain shell commands run directly on the runner.

The three most important structural rules:

  1. Jobs run in parallel by default. If you have job-a and job-b defined at the same level, they start simultaneously. To enforce ordering, use needs: [job-a] in job-b.
  2. Steps within a job run sequentially. If any step fails (non-zero exit code), subsequent steps are skipped and the job fails — unless you add continue-on-error: true or an if: condition.
  3. Each job gets a fresh runner. Files created in job-a do not automatically appear in job-b. You must use actions/upload-artifact and actions/download-artifact to pass files between jobs.

The concurrency block is a production essential that beginners often miss. Without it, if a developer pushes two commits in quick succession, two workflow runs execute simultaneously — wasting compute minutes and potentially causing race conditions in deployments. The cancel-in-progress: true setting automatically cancels the older run when a newer one starts for the same branch.

Interview Tip

Interviewers frequently ask: "How do you prevent two deployments from running simultaneously in GitHub Actions?" The answer is the concurrency block with cancel-in-progress: true for CI, or cancel-in-progress: false for deployments (where you want to queue, not cancel, an in-flight deploy). Knowing the distinction between CI and deployment concurrency behavior signals production experience.

This is one of 18 chapters

Every chapter is free — Kubernetes, Terraform, SRE, distributed systems, and more — with fast daily review built in.

Sign up free