GitHub Actions: Dependencies and Concurrency

GitHub Actions: Dependencies and Concurrency
"DevOps is not about doing things fast; it is about doing them in the right order."
Imagine you have a pipeline that deploys your website to Production.
- Developer A pushes code. The deployment starts.
- $10$ seconds later, Developer B pushes code. A SECOND deployment starts.
- The Disaster: They both try to update the database at the same millisecond. Your website crashes.
Concurrency Groups solve this by telling GitHub: "Only one deployment at a time!" Workflow Dependencies solve the order: "Don't deploy until the tests are Green!" This 1,500+ word guide is your architectural manual for the Logic of Order.
1. Concurrency Groups: The "One-Way" Gate
A concurrency group ensures that only one "Instance" of a job runs for a specific group name.
concurrency:
group: production_deploy
cancel-in-progress: trueWhy this is Professional: When Developer B pushes their code, GitHub sees that Developer A is already deploying. It "Kills" Developer A's job and starts the new one. This ensures that the Latest Code is always the one that wins.
2. Job Dependencies: The needs Keyword
Inside a single YAML file, jobs run in Parallel (all at once) by default.
- You don't want to "Deploy" while the "Tests" are still running.
- You use
needs.
jobs:
test:
runs-on: ubuntu-latest
deploy:
needs: test # Won't start until tests are Green
runs-on: ubuntu-latest3. Workflow Dependencies: workflow_run
Sometimes you have two Separate Files.
- File A: Builds your mobile app.
- File B: Sends a Slack notification.
You can tell File B to wait for File A using the
workflow_runtrigger.
on:
workflow_run:
workflows: ["Build App"]
types: [completed]4. The "Failure Propagation" Rule
What if you have 5 jobs that all "Need" each other?
Job 1 -> Job 2 -> Job 3.
- If Job 1 fails, Job 2 and 3 are automatically cancelled.
- This stops you from wasting money and time on a "Gauranteed Failure."
5. Performance: Grouping by Branch
You can make your concurrency groups smarter by including the branch name.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}The Benefit: This allows multiple developers to work on DIFFERENT features at the same time without "Killing" each other's test runs. Only deployments to the SAME branch will clash.
Summary: The Order Checklist
- Concurrency Groups: Mandatory for any job that touches a Database or Cloud server.
- Needs Keyword: Use it to create a "Waterfall" logic (Test -> Build -> Ship).
- Workflow_Run: Use it to connect separate YAML files into one "Master Pipeline."
- Cancel-in-progress: Always set to
truefor branch deployments to save GitHub Action minutes. - Failure Awareness: Ensure your later jobs don't start if the early jobs are Red.
Dependencies and Concurrency are the "Orchestration" of your engineering. By mastering the gates of the needs keyword and the safety of concurrency groups, you gain the ability to manage massive, high-velocity teams where code is shipped thousands of times a day with zero clashes. You graduate from "Running jobs" to "Architecting the Lifecycle."
Frequently Asked Questions
Q: How do you control the order jobs run in a GitHub Actions workflow?
Use the needs keyword on a job to declare its dependencies: needs: [build, test] means that job will not start until both build and test complete successfully. Jobs without needs run in parallel by default. You can create complex DAGs (directed acyclic graphs) by chaining needs across multiple jobs to express your exact pipeline order.
Q: What does the concurrency key do in GitHub Actions and when should you use it?
concurrency limits how many workflow runs (or jobs) with the same group key can run simultaneously. Set it at the workflow level to cancel in-progress runs when a new commit is pushed: concurrency: { group: "${{ github.ref }}", cancel-in-progress: true }. This prevents queuing up multiple redundant runs on a branch and is essential for pull request workflows where only the latest commit matters.
Q: How do you prevent a deployment job from running while another deployment is in progress?
Use concurrency with cancel-in-progress: false on your deploy job — this queues new deployments instead of cancelling them: concurrency: { group: "production-deploy", cancel-in-progress: false }. Combined with GitHub Environments and required reviewers, this ensures deployments are serialised and each one waits for the previous to finish rather than overwriting a running deploy.
Part of the GitHub Mastery Course — engineering the queue.
