{"id":49473,"date":"2025-05-26T19:05:08","date_gmt":"2025-05-26T19:05:08","guid":{"rendered":"https:\/\/www.devopsschool.com\/blog\/?p=49473"},"modified":"2026-02-21T07:28:48","modified_gmt":"2026-02-21T07:28:48","slug":"gitlab-ci-cd-execution-hierarchy","status":"publish","type":"post","link":"https:\/\/www.devopsschool.com\/blog\/gitlab-ci-cd-execution-hierarchy\/","title":{"rendered":"GitLab CI\/CD Execution Hierarchy"},"content":{"rendered":"\n<p>Understanding the <strong>hierarchy, precedence, sequencing, and parallelism<\/strong> in <strong>GitLab CI\/CD pipelines<\/strong> is crucial to mastering how your jobs run, how to optimize them, and how GitLab decides what to execute and when.<\/p>\n\n\n\n<p>Here\u2019s a <strong>complete and up-to-date (GitLab 18.0, May 2026)<\/strong> breakdown of the <strong>GitLab pipeline execution model<\/strong>:<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h2 class=\"wp-block-heading\">\ud83e\uddf1 1. \ud83d\udd04 GitLab CI\/CD Execution Hierarchy<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">\u27a4 <strong>Pipeline<\/strong> <em>(Top-Level Entity)<\/em><\/h3>\n\n\n\n<p>A single run of your <code>.gitlab-ci.yml<\/code> file. Triggered by:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Push\/merge\/tag<\/li>\n\n\n\n<li>Schedule<\/li>\n\n\n\n<li>Manual trigger<\/li>\n\n\n\n<li>API call<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">\u27a4 <strong>Stages<\/strong> <em>(Sequential Execution Layer)<\/em><\/h3>\n\n\n\n<p>Defines the <strong>order<\/strong> of execution \u2014 each stage completes fully before the next begins.<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">stages:\n  - lint\n  - test\n  - build\n  - deploy\n<\/code><\/span><\/pre>\n\n\n<h3 class=\"wp-block-heading\">\u27a4 <strong>Jobs<\/strong> <em>(Inside Each Stage)<\/em><\/h3>\n\n\n\n<p>All jobs within a stage <strong>run in parallel<\/strong>, provided runners are available.<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">lint:\n  stage: lint\n  script: npm run lint\n\nunit_test:\n  stage: test\n  script: npm test\n<\/code><\/span><\/pre>\n\n\n<h3 class=\"wp-block-heading\">\u27a4 <strong>Steps inside a Job<\/strong><\/h3>\n\n\n\n<p>Each job\u2019s <code>script:<\/code> section contains commands that <strong>run sequentially<\/strong> inside the job&#8217;s shell or container.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\udd03 2. Pipeline Execution Flow<\/h2>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">Pipeline\n \u251c\u2500\u2500 Stage 1: lint\n \u2502    \u251c\u2500\u2500 job: lint_a  (parallel)\n \u2502    \u2514\u2500\u2500 job: lint_b  (parallel)\n \u251c\u2500\u2500 Stage 2: test\n \u2502    \u251c\u2500\u2500 job: unit_tests\n \u2502    \u2514\u2500\u2500 job: integration_tests\n \u251c\u2500\u2500 Stage 3: build\n \u2502    \u2514\u2500\u2500 docker_build\n \u2514\u2500\u2500 Stage 4: deploy\n      \u251c\u2500\u2500 job: staging_deploy\n      \u2514\u2500\u2500 job: prod_deploy (manual)\n<\/code><\/span><\/pre>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h2 class=\"wp-block-heading\">\u23f1\ufe0f 3. Job Precedence &amp; Order of Execution<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">\u2705 <strong>Within a Stage<\/strong>:<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Jobs <strong>run in parallel<\/strong><\/li>\n\n\n\n<li>No strict order unless using <code>needs:<\/code> (see below)<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">\u2705 <strong>Between Stages<\/strong>:<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Sequential<\/strong>: Stage 2 starts <strong>only if<\/strong> all Stage 1 jobs <strong>succeed<\/strong><\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h2 class=\"wp-block-heading\">\u26a1 4. How to Run Jobs in Parallel or Control Order<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">\ud83d\udd39 <strong>Parallel Jobs<\/strong><\/h3>\n\n\n\n<p>Jobs in the same stage naturally run in parallel. Example:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">test_backend:\n  stage: test\n  script: run backend tests\n\ntest_frontend:\n  stage: test\n  script: run frontend tests\n<\/code><\/span><\/pre>\n\n\n<h3 class=\"wp-block-heading\">\ud83d\udd39 <strong>Needs: (Run jobs out-of-order \/ faster)<\/strong><\/h3>\n\n\n\n<p>Allows <strong>stage-skipping<\/strong> and job-level dependency. Ideal for reducing pipeline time.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">unit_test:\n  stage: test\n  script: run tests\n\ndocker_build:\n  stage: build\n  script: build docker\n  needs: &#91;unit_test]   <span class=\"hljs-comment\"># Doesn't wait for whole test stage<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">\ud83d\udd39 <strong>Dependencies<\/strong> (Job artifact consumption, older method)<\/h3>\n\n\n\n<p>Specify jobs that must complete before current job <strong>can use their artifacts<\/strong>.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">deploy<\/span>:\n  <span class=\"hljs-selector-tag\">stage<\/span>: <span class=\"hljs-selector-tag\">deploy<\/span>\n  <span class=\"hljs-selector-tag\">dependencies<\/span>: <span class=\"hljs-selector-attr\">&#91;build]<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>\ud83d\udd01 Use <code>needs:<\/code> for parallel dependency-based optimization<br>\ud83d\udce6 Use <code>dependencies:<\/code> to pass artifacts<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h2 class=\"wp-block-heading\">\ud83e\uddea 5. Conditional Execution (Job-Level Control)<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">\ud83d\udd38 <strong>Rules<\/strong><\/h3>\n\n\n\n<p>Recommended way to control job execution with complex conditions.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">job_a:\n  rules:\n    - <span class=\"hljs-keyword\">if<\/span>: <span class=\"hljs-string\">'$CI_COMMIT_BRANCH == \"main\"'<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">\ud83d\udd38 <strong>only\/except<\/strong> (Deprecated in favor of <code>rules<\/code>)<\/h3>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">job_b:\n  only:\n    - branches\n    - tags\n<\/code><\/span><\/pre>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h2 class=\"wp-block-heading\">\ud83c\udfaf 6. Extended Structures<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Structure<\/th><th>Purpose<\/th><th>Notes<\/th><\/tr><\/thead><tbody><tr><td><strong>Parent-Child Pipelines<\/strong><\/td><td>Modularize pipelines (include from other <code>.yml<\/code>)<\/td><td>Ideal for monorepos<\/td><\/tr><tr><td><strong>Multi-project Pipelines<\/strong><\/td><td>Trigger another project\u2019s pipeline<\/td><td>Good for microservice chaining<\/td><\/tr><tr><td><strong>Includes<\/strong><\/td><td>Reuse YAML templates<\/td><td>From same repo or remote<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\udccb 7. Visual: GitLab CI\/CD Execution Hierarchy<\/h2>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">Pipeline\n\u251c\u2500\u2500 Stages (sequential)\n\u2502   \u251c\u2500\u2500 Jobs (parallel unless controlled)\n\u2502   \u2502   \u251c\u2500\u2500 Scripts (sequential commands)\n\u2502   \u2502   \u2514\u2500\u2500 Artifacts\/Needs\/Dependencies\n\u251c\u2500\u2500 Includes \/ Child Pipelines (optional)\n\u2514\u2500\u2500 Triggered Pipelines (optional)\n<\/code><\/span><\/pre>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h2 class=\"wp-block-heading\">\u2705 Summary: Controlling Flow &amp; Parallelism<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Control Mechanism<\/th><th>Used For<\/th><\/tr><\/thead><tbody><tr><td><code>stages:<\/code><\/td><td>Define sequential job groupings<\/td><\/tr><tr><td><code>needs:<\/code><\/td><td>Define parallel dependencies<\/td><\/tr><tr><td><code>rules:<\/code><\/td><td>Fine-grained control of job triggers<\/td><\/tr><tr><td><code>when:<\/code><\/td><td>Delay, manual, or conditional jobs<\/td><\/tr><tr><td><code>only\/except<\/code><\/td><td>Basic conditions (legacy)<\/td><\/tr><tr><td><code>dependencies:<\/code><\/td><td>Artifact-based job dependencies<\/td><\/tr><tr><td><code>trigger:<\/code><\/td><td>Trigger child or multi-project pipelines<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Understanding the hierarchy, precedence, sequencing, and parallelism in GitLab CI\/CD pipelines is crucial to mastering how your jobs run, how to optimize them, and how GitLab decides what to execute&#8230; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"_joinchat":[],"footnotes":""},"categories":[2],"tags":[],"class_list":["post-49473","post","type-post","status-publish","format-standard","hentry","category-uncategorised"],"_links":{"self":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/49473","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/comments?post=49473"}],"version-history":[{"count":2,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/49473\/revisions"}],"predecessor-version":[{"id":58986,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/49473\/revisions\/58986"}],"wp:attachment":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media?parent=49473"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/categories?post=49473"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/tags?post=49473"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}