Optimizing GitHub Actions: Ensuring Only the Latest Merge Builds in Monorepos for Better Software Project KPIs
The Monorepo Merge Challenge: When Concurrency Isn't Enough
In the fast-paced world of monorepos, it's common for multiple Pull Requests (PRs) to be merged into the main branch almost simultaneously. For teams relying on GitHub Actions to build critical artifacts like Docker images, this can create a significant challenge. While GitHub Actions offers concurrency groups with cancel-in-progress to prevent parallel runs, it explicitly states that "ordering is not guaranteed." This means an older workflow run might inadvertently cancel a newer one, or worse, complete an unnecessary build that's immediately superseded by a subsequent merge.
This exact pain point was highlighted in a recent GitHub Community discussion, where a user described wanting to build Docker images only for the latest PR merged into main, canceling all other concurrent builds. The arbitrary ordering of concurrency groups meant this desired "latest PR wins" behavior was not reliably achievable out-of-the-box, leading to wasted CI minutes and potential confusion.
The Real Goal: Build Only If This Commit is Still HEAD of main
The community quickly converged on a crucial reframing of the problem: instead of trying to force GitHub Actions to guarantee a Last-In, First-Out (LIFO) queue for concurrency, the true objective is to "only build if this commit is still the tip of main." Once this perspective is adopted, the solution becomes robust and reliable, independent of the order in which workflows are initiated.
The Reliable Solution: Concurrency + HEAD Check
The recommended approach combines GitHub Actions' built-in concurrency feature with a crucial runtime check. This two-step strategy ensures that only the most relevant build proceeds, effectively eliminating race conditions.
Step 1: Use concurrency to Manage Parallel Runs
The first step is to continue using concurrency with cancel-in-progress: true. This is vital for preventing multiple expensive builds from running simultaneously and ensuring that if a newer workflow starts, older ones are promptly canceled. While it doesn't guarantee which run ultimately completes, it manages the overall queue and prevents resource contention.
jobs:
build:
runs-on: ubuntu-latest
concurrency:
group: build-main-${{ github.ref }}
cancel-in-progress: true
steps:
# ... (subsequent steps)
Step 2: Implement a Guard for the Latest Commit
The critical addition is a "guard" step at the beginning of your job. This step checks if the current workflow's GITHUB_SHA (the commit that triggered the workflow) is still the absolute latest commit on the main branch. If a newer commit has been merged since the workflow started, the job exits early, preventing any unnecessary resource consumption. This check eliminates all timing ambiguity.
jobs:
build:
runs-on: ubuntu-latest
concurrency:
group: build-main-${{ github.ref }}
cancel-in-progress: true
steps:
- name: Check if this is latest commit on main
run: |
git fetch origin main
LATEST=$(git rev-parse origin/main)
if [ "$LATEST" != "${{ github.sha }}" ]; then
echo "A newer commit exists on main. Canceling this run."
exit 0
fi
# ... (your actual build steps, e.g., building Docker images)
This pattern is widely adopted in large-scale monorepos because it's resilient. Even if workflows start in an unexpected order, only the workflow associated with the true HEAD of main will proceed to the expensive build steps.
Impact on Software Project KPIs and Productivity
This refined approach to managing builds in a monorepo directly impacts several critical software project KPIs. By preventing redundant builds, teams significantly reduce CI/CD costs and optimize resource utilization. Developers experience faster, more reliable feedback loops, as they can trust that the built artifacts reflect the absolute latest state of the main branch. This efficiency boost contributes to higher deployment frequency, improved lead time for changes, and ultimately, a more productive development environment. It's a prime example of how thoughtful workflow configuration can translate into tangible improvements in project performance and team morale.
In summary, while GitHub Actions' concurrency is powerful, it's not a silver bullet for guaranteeing build order. By combining it with a simple, yet effective, runtime check for the latest commit, you can ensure your CI/CD pipelines are both efficient and accurate, directly contributing to better project outcomes and developer satisfaction.