Navigating GitHub Actions: Workflow Architecture, YAML Anchors, and Automation Realities

GitHub Actions has established itself as a foundational component of modern software development lifecycles, offering a robust platform for automating workflows directly within the GitHub ecosystem. At its core, the system relies on YAML syntax to define configurable, automated processes that execute jobs in response to specific events. Understanding the architectural requirements for workflow creation, the nuances of trigger mechanisms, and the recent—but limited—implementation of YAML anchors is essential for developers aiming to build maintainable and efficient automation. This analysis explores the structural foundations of GitHub Actions, the practical application of workflow files, and the technical realities surrounding configuration reuse and template visibility.

Workflow Structure and File Placement

The foundational unit of automation in GitHub Actions is the workflow, defined as a configurable automated process that runs one or more jobs. These workflows are defined by YAML files that are checked into a repository and are executed when triggered by an event, manually, or at a defined schedule. To ensure GitHub can discover and execute these automations, strict directory conventions must be followed. Workflow files must be stored in a directory named .github/workflows within the repository. While the filename can be chosen freely, it must use the .yml or .yaml extension, reflecting the underlying markup language used for configuration.

A repository can contain multiple workflows, each designed to perform different sets of tasks. Common use cases include building and testing pull requests, deploying applications upon release creation, or adding labels when new issues are opened. Regardless of the specific task, every workflow must contain two basic components: one or more events that trigger the workflow, and one or more jobs. Each job executes on a runner machine and consists of a series of steps. These steps can either run a user-defined script or execute an action, which serves as a reusable extension to simplify the workflow logic.

Trigger Events and Job Composition

Workflow triggers are defined using the on key in the YAML configuration. These triggers correspond to events that cause the workflow to run. Events can originate from within the repository, such as a push to a specific branch, the creation of a release, or the opening of an issue. Triggers can also be external, utilizing repository_dispatch events, scheduled times, or manual initiation. For instance, a workflow can be configured to run automatically whenever code is pushed to the default branch.

Once triggered, the workflow executes jobs. Each job runs on a runner machine, specified by the runs-on parameter, such as ubuntu-latest. Within each job, steps are executed sequentially. Steps can utilize pre-built actions from the GitHub marketplace or community, or they can execute custom shell commands. For example, a basic workflow might include a step to check out the pushed code using actions/checkout@v6, followed by steps to install dependencies and run specific commands. Contextual variables, such as ${{ github.actor }} for the user initiating the workflow or ${{ github.event_name }} for the triggering event, allow for dynamic run names and output messages, providing visibility into the automation's state.

Creating and Committing Workflow Files

The process of creating a workflow begins with file creation within the repository's file system. If the .github/workflows directory does not already exist, it must be created along with the workflow file. This can be achieved by navigating to the repository on GitHub, clicking "Add file," and selecting "Create new file." The file path should be specified as .github/workflows/<filename>.yml. This action creates the .github directory, the workflows subdirectory, and the workflow file in a single step. If the directory already exists, the user navigates to it and creates the new file directly.

Once the YAML content is added, the changes must be committed to the repository. Users can choose to commit to the default branch or create a new branch and start a pull request. Upon successful commit, the workflow file is installed in the repository and will run automatically according to the defined triggers. For example, a simple workflow named learn-github-actions.yml might define a job that checks out the code, installs the Bats testing framework via npm, and outputs the version using the command bats -v. This immediate feedback loop confirms that the workflow is active and executing as expected.

YAML Anchors and Configuration Reuse

A significant community request addressed in September 2025 was the introduction of YAML anchors in GitHub Actions. This feature allows users to reuse configuration blocks across workflows, promoting better conformance with the YAML specification and reducing duplication within a single file. The feature is automatically enabled for all users and repositories, requiring no additional configuration. YAML anchors eliminate duplication within one file with zero setup overhead, avoiding the need for separate files or complex input definitions associated with other reuse methods.

However, the implementation of YAML anchors in GitHub Actions has drawn criticism for its limitations. Notably, merge keys are not supported. Merge keys, a feature of the YAML 1.1 specification often used in combination with anchors to compose configuration blocks, are absent from GitHub's implementation. This omission is significant because many other CI/CD platforms, including GitLab, Bitbucket, and CircleCI, support full YAML anchor functionality, including merge keys. The lack of merge key support means that while users can reference duplicate blocks, they cannot extend or merge them as easily as in other systems. This has led to perceptions that the feature is half-baked, as it addresses syntax compliance but falls short of providing the full compositional power that the community requested.

Template Visibility and Job Context

Alongside anchor support, GitHub Actions updated its handling of workflow templates. Previously, workflow templates had to reside in a public repository named .github. Now, templates can be stored in non-public .github repositories. If the .github repository is internal, internal and private repositories can utilize these templates. If it is private, only private repositories can access them. This change enhances security and organizational control, allowing sensitive automation patterns to be shared without exposing them publicly. It is important to note that this visibility change applies only to GitHub Actions; other products using .github repositories, such as GitHub Issues, continue to require public repositories for their templates.

Additionally, GitHub introduced the check_run_id value in the job context. This addition allows developers to identify the currently running job directly from within that job by accessing the check_run_id. This contextual information aids in debugging and monitoring, providing a direct link between the workflow execution and the specific check run generated on GitHub.

Alternatives to YAML Anchors

For developers seeking to eliminate duplication before or despite the introduction of YAML anchors, alternative methods exist, each with distinct trade-offs. Reusable workflows allow for sharing entire workflows across repositories, making them ideal for organization-wide deployment patterns. However, they are often overkill for simple duplication within a single workflow, and they do not allow adding steps before or after the reusable workflow call.

Composite actions offer another avenue for reuse. These bundle step sequences into reusable actions stored in .github/actions/. They provide proper encapsulation with inputs and outputs and work cross-repository. However, they require separate action.yml files, cannot specify runners directly, and add invocation overhead. For simple within-file duplication, composite actions can feel heavyweight compared to the zero-setup overhead of YAML anchors, despite the latter's limitations regarding merge keys.

Conclusion

GitHub Actions provides a powerful framework for automating software development workflows through YAML-defined processes. The requirement to store workflows in .github/workflows and the reliance on trigger events and job steps form the backbone of this system. Recent updates, including the support for YAML anchors and non-public workflow templates, aim to enhance maintainability and security. However, the absence of merge key support in YAML anchors represents a significant technical limitation that distinguishes GitHub's implementation from other CI/CD platforms. Developers must carefully weigh the benefits of in-file anchor reuse against the constraints imposed by this partial implementation, considering alternatives like reusable workflows and composite actions based on their specific architectural needs. As the platform continues to evolve, understanding these nuances is critical for effective automation strategy.

Sources

  1. Create an example workflow - GitHub Docs
  2. Actions YAML anchors and non-public workflow templates - GitHub Changelog
  3. Workflows - GitHub Docs
  4. Quickstart for GitHub Actions - GitHub Docs
  5. GitHub Actions YAML Anchors, Aliases, Merge Keys - Frenck.dev

Related Posts