[{"data":1,"prerenderedAt":1757},["ShallowReactive",2],{"/blog/building-a-gitlab-ci-cd-pipeline-for-a-monorepo-the-easy-way":3,"navigation-en-us":970,"banner-en-us":1397,"footer-en-us":1407,"blog-post-authors-en-us-Sam Morris":1652,"blog-related-posts-en-us-building-a-gitlab-ci-cd-pipeline-for-a-monorepo-the-easy-way":1667,"blog-promotions-en-us":1693,"next-steps-en-us":1747},{"id":4,"title":5,"authors":6,"body":8,"category":951,"date":952,"description":953,"extension":954,"externalUrl":955,"faq":955,"featured":956,"heroImage":957,"meta":958,"navigation":117,"path":959,"seo":960,"slug":964,"stem":965,"tags":966,"template":968,"updatedDate":955,"__hash__":969},"blogPosts/en-us/blog/building-a-gitlab-ci-cd-pipeline-for-a-monorepo-the-easy-way.md","Building a GitLab CI/CD pipeline for a monorepo the easy way",[7],"Sam Morris",{"type":9,"value":10,"toc":945},"minimark",[11,22,27,30,41,45,48,59,64,193,202,207,361,366,508,521,532,536,549,576,581,708,711,715,804,808,897,911,919,923,941],[12,13,14,15,21],"p",{},"Monorepos allow you to host multiple applications’ code in a single repository. In GitLab, that involves placing disparate application source code in separate directories in one project. While this strategy allows for version controlled storage of your code, it was tricky leveraging the full power of GitLab’s ",[16,17,20],"a",{"href":18,"rel":19},"https://about.gitlab.com/topics/ci-cd/",[],"CI/CD"," pipeline capabilities… until now!",[23,24,26],"h2",{"id":25},"the-ideal-case-cicd-in-a-monorepo","The ideal case: CI/CD in a monorepo",[12,28,29],{},"Since you have more than one application’s code living in your repository, you will want to have more than one pipeline configuration. For example, if you have a .NET application and a Spring application in one project, each application may have different build and test jobs to complete. Ideally, you can completely decouple the pipelines and only run each pipeline based on changes to that specific application’s source code.",[12,31,32,33,37,38,40],{},"The technical approach for this would be to have a project-level ",[34,35,36],"code",{},".gitlab-ci.yml"," pipeline configuration file that includes a specific YAML file based on changes in a certain directory. The ",[34,39,36],{}," pipeline serves as the control plane that triggers the appropriate pipeline based on the changes made to the code.",[23,42,44],{"id":43},"the-legacy-approach","The legacy approach",[12,46,47],{},"Prior to GitLab 16.4, we were not able to include a YAML file based on changes to a directory or file in a project. However, we could accomplish this functionality via a workaround.",[12,49,50,51,54,55,58],{},"In our monorepo project, we have two directories for different applications. In this example, there are ",[34,52,53],{},"java"," and ",[34,56,57],{},"python"," directories representing a Java and Python app, respectively. Each directory has an application-specific YAML file to build each app. In the project’s pipeline file, we simply include both application pipeline files, and do the logic handling in those files directly.",[12,60,61,63],{},[34,62,36],{},":",[65,66,71],"pre",{"className":67,"code":68,"language":69,"meta":70,"style":70},"language-yaml shiki shiki-themes github-light","stages:\n  - build\n  - test\n  - deploy\n\ntop-level-job:\n  stage: build\n  script:\n    - echo \"Hello world...\"\n\ninclude:\n  - local: '/java/j.gitlab-ci.yml'\n  - local: '/python/py.gitlab-ci.yml'\n\n","yaml","",[34,72,73,86,96,104,112,119,127,138,146,155,160,168,181],{"__ignoreMap":70},[74,75,78,82],"span",{"class":76,"line":77},"line",1,[74,79,81],{"class":80},"shJU0","stages",[74,83,85],{"class":84},"sgsFI",":\n",[74,87,89,92],{"class":76,"line":88},2,[74,90,91],{"class":84},"  - ",[74,93,95],{"class":94},"sYBdl","build\n",[74,97,99,101],{"class":76,"line":98},3,[74,100,91],{"class":84},[74,102,103],{"class":94},"test\n",[74,105,107,109],{"class":76,"line":106},4,[74,108,91],{"class":84},[74,110,111],{"class":94},"deploy\n",[74,113,115],{"class":76,"line":114},5,[74,116,118],{"emptyLinePlaceholder":117},true,"\n",[74,120,122,125],{"class":76,"line":121},6,[74,123,124],{"class":80},"top-level-job",[74,126,85],{"class":84},[74,128,130,133,136],{"class":76,"line":129},7,[74,131,132],{"class":80},"  stage",[74,134,135],{"class":84},": ",[74,137,95],{"class":94},[74,139,141,144],{"class":76,"line":140},8,[74,142,143],{"class":80},"  script",[74,145,85],{"class":84},[74,147,149,152],{"class":76,"line":148},9,[74,150,151],{"class":84},"    - ",[74,153,154],{"class":94},"echo \"Hello world...\"\n",[74,156,158],{"class":76,"line":157},10,[74,159,118],{"emptyLinePlaceholder":117},[74,161,163,166],{"class":76,"line":162},11,[74,164,165],{"class":80},"include",[74,167,85],{"class":84},[74,169,171,173,176,178],{"class":76,"line":170},12,[74,172,91],{"class":84},[74,174,175],{"class":80},"local",[74,177,135],{"class":84},[74,179,180],{"class":94},"'/java/j.gitlab-ci.yml'\n",[74,182,184,186,188,190],{"class":76,"line":183},13,[74,185,91],{"class":84},[74,187,175],{"class":80},[74,189,135],{"class":84},[74,191,192],{"class":94},"'/python/py.gitlab-ci.yml'\n",[12,194,195,196,201],{},"In each application-specific pipeline file, we create a hidden job named .java-common or .python-common that only runs if there are changes to that app’s directory. ",[16,197,200],{"href":198,"rel":199},"https://docs.gitlab.com/ci/jobs/#hide-jobs",[],"Hidden jobs"," do not run by default, and are often utilized to reuse specific job configurations. Each pipeline extends that hidden job to inherit the rules defining which files to watch for changes, which would then initiate the pipeline job.",[12,203,204,63],{},[34,205,206],{},"j.gitlab-ci.yml",[65,208,210],{"className":67,"code":209,"language":69,"meta":70,"style":70},"stages:\n  - build\n  - test\n  - deploy\n\n.java-common:\n  rules:\n    - changes:\n      - '../java/*'\n\njava-build-job:\n  extends: .java-common\n  stage: build\n  script:\n    - echo \"Building Java\"\n\njava-test-job:\n  extends: .java-common\n  stage: test\n  script:\n    - echo \"Testing Java\"\n\n",[34,211,212,218,224,230,236,240,247,254,263,271,275,282,292,300,307,315,320,328,337,346,353],{"__ignoreMap":70},[74,213,214,216],{"class":76,"line":77},[74,215,81],{"class":80},[74,217,85],{"class":84},[74,219,220,222],{"class":76,"line":88},[74,221,91],{"class":84},[74,223,95],{"class":94},[74,225,226,228],{"class":76,"line":98},[74,227,91],{"class":84},[74,229,103],{"class":94},[74,231,232,234],{"class":76,"line":106},[74,233,91],{"class":84},[74,235,111],{"class":94},[74,237,238],{"class":76,"line":114},[74,239,118],{"emptyLinePlaceholder":117},[74,241,242,245],{"class":76,"line":121},[74,243,244],{"class":80},".java-common",[74,246,85],{"class":84},[74,248,249,252],{"class":76,"line":129},[74,250,251],{"class":80},"  rules",[74,253,85],{"class":84},[74,255,256,258,261],{"class":76,"line":140},[74,257,151],{"class":84},[74,259,260],{"class":80},"changes",[74,262,85],{"class":84},[74,264,265,268],{"class":76,"line":148},[74,266,267],{"class":84},"      - ",[74,269,270],{"class":94},"'../java/*'\n",[74,272,273],{"class":76,"line":157},[74,274,118],{"emptyLinePlaceholder":117},[74,276,277,280],{"class":76,"line":162},[74,278,279],{"class":80},"java-build-job",[74,281,85],{"class":84},[74,283,284,287,289],{"class":76,"line":170},[74,285,286],{"class":80},"  extends",[74,288,135],{"class":84},[74,290,291],{"class":94},".java-common\n",[74,293,294,296,298],{"class":76,"line":183},[74,295,132],{"class":80},[74,297,135],{"class":84},[74,299,95],{"class":94},[74,301,303,305],{"class":76,"line":302},14,[74,304,143],{"class":80},[74,306,85],{"class":84},[74,308,310,312],{"class":76,"line":309},15,[74,311,151],{"class":84},[74,313,314],{"class":94},"echo \"Building Java\"\n",[74,316,318],{"class":76,"line":317},16,[74,319,118],{"emptyLinePlaceholder":117},[74,321,323,326],{"class":76,"line":322},17,[74,324,325],{"class":80},"java-test-job",[74,327,85],{"class":84},[74,329,331,333,335],{"class":76,"line":330},18,[74,332,286],{"class":80},[74,334,135],{"class":84},[74,336,291],{"class":94},[74,338,340,342,344],{"class":76,"line":339},19,[74,341,132],{"class":80},[74,343,135],{"class":84},[74,345,103],{"class":94},[74,347,349,351],{"class":76,"line":348},20,[74,350,143],{"class":80},[74,352,85],{"class":84},[74,354,356,358],{"class":76,"line":355},21,[74,357,151],{"class":84},[74,359,360],{"class":94},"echo \"Testing Java\"\n",[12,362,363,63],{},[34,364,365],{},"py.gitlab-ci.yml",[65,367,369],{"className":67,"code":368,"language":69,"meta":70,"style":70},"stages:\n  - build\n  - test\n  - deploy\n\n.python-common:\n  rules:\n    - changes:\n      - '../python/*'\n\npython-build-job:\n  extends: .python-common\n  stage: build\n  script:\n    - echo \"Building Python\"\n\npython-test-job:\n  extends: .python-common\n  stage: test\n  script:\n    - echo \"Testing Python\"\n\n",[34,370,371,377,383,389,395,399,406,412,420,427,431,438,447,455,461,468,472,479,487,495,501],{"__ignoreMap":70},[74,372,373,375],{"class":76,"line":77},[74,374,81],{"class":80},[74,376,85],{"class":84},[74,378,379,381],{"class":76,"line":88},[74,380,91],{"class":84},[74,382,95],{"class":94},[74,384,385,387],{"class":76,"line":98},[74,386,91],{"class":84},[74,388,103],{"class":94},[74,390,391,393],{"class":76,"line":106},[74,392,91],{"class":84},[74,394,111],{"class":94},[74,396,397],{"class":76,"line":114},[74,398,118],{"emptyLinePlaceholder":117},[74,400,401,404],{"class":76,"line":121},[74,402,403],{"class":80},".python-common",[74,405,85],{"class":84},[74,407,408,410],{"class":76,"line":129},[74,409,251],{"class":80},[74,411,85],{"class":84},[74,413,414,416,418],{"class":76,"line":140},[74,415,151],{"class":84},[74,417,260],{"class":80},[74,419,85],{"class":84},[74,421,422,424],{"class":76,"line":148},[74,423,267],{"class":84},[74,425,426],{"class":94},"'../python/*'\n",[74,428,429],{"class":76,"line":157},[74,430,118],{"emptyLinePlaceholder":117},[74,432,433,436],{"class":76,"line":162},[74,434,435],{"class":80},"python-build-job",[74,437,85],{"class":84},[74,439,440,442,444],{"class":76,"line":170},[74,441,286],{"class":80},[74,443,135],{"class":84},[74,445,446],{"class":94},".python-common\n",[74,448,449,451,453],{"class":76,"line":183},[74,450,132],{"class":80},[74,452,135],{"class":84},[74,454,95],{"class":94},[74,456,457,459],{"class":76,"line":302},[74,458,143],{"class":80},[74,460,85],{"class":84},[74,462,463,465],{"class":76,"line":309},[74,464,151],{"class":84},[74,466,467],{"class":94},"echo \"Building Python\"\n",[74,469,470],{"class":76,"line":317},[74,471,118],{"emptyLinePlaceholder":117},[74,473,474,477],{"class":76,"line":322},[74,475,476],{"class":80},"python-test-job",[74,478,85],{"class":84},[74,480,481,483,485],{"class":76,"line":330},[74,482,286],{"class":80},[74,484,135],{"class":84},[74,486,446],{"class":94},[74,488,489,491,493],{"class":76,"line":339},[74,490,132],{"class":80},[74,492,135],{"class":84},[74,494,103],{"class":94},[74,496,497,499],{"class":76,"line":348},[74,498,143],{"class":80},[74,500,85],{"class":84},[74,502,503,505],{"class":76,"line":355},[74,504,151],{"class":84},[74,506,507],{"class":94},"echo \"Testing Python\"\n",[12,509,510,511,514,515,520],{},"There are some downsides to this, including having to extend the job for each other job in the YAML file to ensure it complies with the rules, creating a lot of redundant code and room for human error. Additionally, extended jobs cannot have duplicate keys, so you could not define your own ",[34,512,513],{},"rules"," logic in each job since there would be a collision in the keys and their ",[16,516,519],{"href":517,"rel":518},"https://docs.gitlab.com/ci/yaml/#extends",[],"values are not merged",".",[12,522,523,524,527,528,531],{},"This results in a pipeline running that includes the j.gitlab-ci.yml jobs when ",[34,525,526],{},"java/"," is updated, and py.gitlab-ci.yml when ",[34,529,530],{},"python/"," is updated.",[23,533,535],{"id":534},"the-new-approach-conditionally-include-pipeline-files","The new approach: Conditionally include pipeline files",[537,538,541,542],"figure",{"className":539},[540],"video_container","\n  ",[543,544,548],"iframe",{"src":545,"frameBorder":546,"allowFullScreen":547},"https://www.youtube.com/embed/6phvk8jioAo?si=y6ztZODvUtM-cHmZ","0","true"," ",[12,550,551,552,563,564,558,566,569,570,572,573,575],{},"In GitLab 16.4, we introduced ",[16,553,556,558,559,562],{"href":554,"rel":555},"https://docs.gitlab.com/ci/yaml/includes/#include-with-ruleschanges",[],[34,557,165],{}," with ",[34,560,561],{},"rules:changes"," for pipelines",". Previously, you could ",[34,565,165],{},[34,567,568],{},"rules:if",", but not ",[34,571,561],{}," making this update extremely powerful. Now, you can simply use the ",[34,574,165],{}," keyword and define the monorepo rules in your project pipeline configuration.",[12,577,578,579,63],{},"New ",[34,580,36],{},[65,582,584],{"className":67,"code":583,"language":69,"meta":70,"style":70},"stages:\n  - build\n  - test\n\ntop-level-job:\n  stage: build\n  script:\n    - echo \"Hello world...\"\n\ninclude:\n  - local: '/java/j.gitlab-ci.yml'\n    rules:\n      - changes:\n        - 'java/*'\n  - local: '/python/py.gitlab-ci.yml'\n    rules:\n      - changes:\n        - 'python/*'\n\n",[34,585,586,592,598,604,608,614,622,628,634,638,644,654,661,669,677,687,693,701],{"__ignoreMap":70},[74,587,588,590],{"class":76,"line":77},[74,589,81],{"class":80},[74,591,85],{"class":84},[74,593,594,596],{"class":76,"line":88},[74,595,91],{"class":84},[74,597,95],{"class":94},[74,599,600,602],{"class":76,"line":98},[74,601,91],{"class":84},[74,603,103],{"class":94},[74,605,606],{"class":76,"line":106},[74,607,118],{"emptyLinePlaceholder":117},[74,609,610,612],{"class":76,"line":114},[74,611,124],{"class":80},[74,613,85],{"class":84},[74,615,616,618,620],{"class":76,"line":121},[74,617,132],{"class":80},[74,619,135],{"class":84},[74,621,95],{"class":94},[74,623,624,626],{"class":76,"line":129},[74,625,143],{"class":80},[74,627,85],{"class":84},[74,629,630,632],{"class":76,"line":140},[74,631,151],{"class":84},[74,633,154],{"class":94},[74,635,636],{"class":76,"line":148},[74,637,118],{"emptyLinePlaceholder":117},[74,639,640,642],{"class":76,"line":157},[74,641,165],{"class":80},[74,643,85],{"class":84},[74,645,646,648,650,652],{"class":76,"line":162},[74,647,91],{"class":84},[74,649,175],{"class":80},[74,651,135],{"class":84},[74,653,180],{"class":94},[74,655,656,659],{"class":76,"line":170},[74,657,658],{"class":80},"    rules",[74,660,85],{"class":84},[74,662,663,665,667],{"class":76,"line":183},[74,664,267],{"class":84},[74,666,260],{"class":80},[74,668,85],{"class":84},[74,670,671,674],{"class":76,"line":302},[74,672,673],{"class":84},"        - ",[74,675,676],{"class":94},"'java/*'\n",[74,678,679,681,683,685],{"class":76,"line":309},[74,680,91],{"class":84},[74,682,175],{"class":80},[74,684,135],{"class":84},[74,686,192],{"class":94},[74,688,689,691],{"class":76,"line":317},[74,690,658],{"class":80},[74,692,85],{"class":84},[74,694,695,697,699],{"class":76,"line":322},[74,696,267],{"class":84},[74,698,260],{"class":80},[74,700,85],{"class":84},[74,702,703,705],{"class":76,"line":330},[74,704,673],{"class":84},[74,706,707],{"class":94},"'python/*'\n",[12,709,710],{},"Then each application’s YAML can just focus on building and testing that application’s code, without extending a hidden job repeatedly. This allows for more flexibility in job definitions and reduces code rewriting for engineers.",[12,712,578,713,63],{},[34,714,206],{},[65,716,718],{"className":67,"code":717,"language":69,"meta":70,"style":70},"stages:\n  - build\n  - test\n  - deploy\n\njava-build-job:\n  stage: build\n  script:\n    - echo \"Building Java\"\n\njava-test-job:\n  stage: test\n  script:\n    - echo \"Testing Java\"\n\n",[34,719,720,726,732,738,744,748,754,762,768,774,778,784,792,798],{"__ignoreMap":70},[74,721,722,724],{"class":76,"line":77},[74,723,81],{"class":80},[74,725,85],{"class":84},[74,727,728,730],{"class":76,"line":88},[74,729,91],{"class":84},[74,731,95],{"class":94},[74,733,734,736],{"class":76,"line":98},[74,735,91],{"class":84},[74,737,103],{"class":94},[74,739,740,742],{"class":76,"line":106},[74,741,91],{"class":84},[74,743,111],{"class":94},[74,745,746],{"class":76,"line":114},[74,747,118],{"emptyLinePlaceholder":117},[74,749,750,752],{"class":76,"line":121},[74,751,279],{"class":80},[74,753,85],{"class":84},[74,755,756,758,760],{"class":76,"line":129},[74,757,132],{"class":80},[74,759,135],{"class":84},[74,761,95],{"class":94},[74,763,764,766],{"class":76,"line":140},[74,765,143],{"class":80},[74,767,85],{"class":84},[74,769,770,772],{"class":76,"line":148},[74,771,151],{"class":84},[74,773,314],{"class":94},[74,775,776],{"class":76,"line":157},[74,777,118],{"emptyLinePlaceholder":117},[74,779,780,782],{"class":76,"line":162},[74,781,325],{"class":80},[74,783,85],{"class":84},[74,785,786,788,790],{"class":76,"line":170},[74,787,132],{"class":80},[74,789,135],{"class":84},[74,791,103],{"class":94},[74,793,794,796],{"class":76,"line":183},[74,795,143],{"class":80},[74,797,85],{"class":84},[74,799,800,802],{"class":76,"line":302},[74,801,151],{"class":84},[74,803,360],{"class":94},[12,805,578,806,63],{},[34,807,365],{},[65,809,811],{"className":67,"code":810,"language":69,"meta":70,"style":70},"stages:\n  - build\n  - test\n  - deploy\n\npython-build-job:\n  stage: build\n  script:\n    - echo \"Building Python\"\n\npython-test-job:\n  stage: test\n  script:\n    - echo \"Testing Python\"\n\n",[34,812,813,819,825,831,837,841,847,855,861,867,871,877,885,891],{"__ignoreMap":70},[74,814,815,817],{"class":76,"line":77},[74,816,81],{"class":80},[74,818,85],{"class":84},[74,820,821,823],{"class":76,"line":88},[74,822,91],{"class":84},[74,824,95],{"class":94},[74,826,827,829],{"class":76,"line":98},[74,828,91],{"class":84},[74,830,103],{"class":94},[74,832,833,835],{"class":76,"line":106},[74,834,91],{"class":84},[74,836,111],{"class":94},[74,838,839],{"class":76,"line":114},[74,840,118],{"emptyLinePlaceholder":117},[74,842,843,845],{"class":76,"line":121},[74,844,435],{"class":80},[74,846,85],{"class":84},[74,848,849,851,853],{"class":76,"line":129},[74,850,132],{"class":80},[74,852,135],{"class":84},[74,854,95],{"class":94},[74,856,857,859],{"class":76,"line":140},[74,858,143],{"class":80},[74,860,85],{"class":84},[74,862,863,865],{"class":76,"line":148},[74,864,151],{"class":84},[74,866,467],{"class":94},[74,868,869],{"class":76,"line":157},[74,870,118],{"emptyLinePlaceholder":117},[74,872,873,875],{"class":76,"line":162},[74,874,476],{"class":80},[74,876,85],{"class":84},[74,878,879,881,883],{"class":76,"line":170},[74,880,132],{"class":80},[74,882,135],{"class":84},[74,884,103],{"class":94},[74,886,887,889],{"class":76,"line":183},[74,888,143],{"class":80},[74,890,85],{"class":84},[74,892,893,895],{"class":76,"line":302},[74,894,151],{"class":84},[74,896,507],{"class":94},[12,898,899,900,907,908,910],{},"This accomplishes the same task of including the Java and Python jobs only when their directories are modified. Something to consider in your implementation is that ",[16,901,904,905],{"href":902,"rel":903},"https://docs.gitlab.com/ci/jobs/job_troubleshooting/#jobs-or-pipelines-run-unexpectedly-when-using-changes",[],"jobs can run unexpectedly when using ",[34,906,260],{},". The changes rule always evaluates to true when pushing a new branch or a new tag to GitLab, so all jobs included will run upon first push to a branch regardless of the ",[34,909,561],{}," definition. You can mitigate this experience by creating your feature branch first and then opening a merge request to begin your development, since the first push to the branch when it is created will force all jobs to run.",[12,912,913,914,558,916,918],{},"Ultimately, monorepos are a strategy that can be used with GitLab and CI/CD, and, with our new ",[34,915,165],{},[34,917,561],{}," feature, we have a better best practice for using GitLab CI with monorepos. To get started with monorepos, take out a free Gitlab Ultimate trial today.",[23,920,922],{"id":921},"more-cicd-resources","More CI/CD resources",[924,925,926,934],"ul",{},[927,928,929],"li",{},[16,930,933],{"href":931,"rel":932},"https://about.gitlab.com/blog/tips-for-managing-monorepos-in-gitlab/",[],"5 tips for managing monorepos in GitLab",[927,935,936],{},[16,937,940],{"href":938,"rel":939},"https://about.gitlab.com/blog/how-to-learn-ci-cd-fast/",[],"How to learn CI/CD fast",[942,943,944],"style",{},"html pre.shiki code .shJU0, html code.shiki .shJU0{--shiki-default:#22863A}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":70,"searchDepth":88,"depth":88,"links":946},[947,948,949,950],{"id":25,"depth":88,"text":26},{"id":43,"depth":88,"text":44},{"id":534,"depth":88,"text":535},{"id":921,"depth":88,"text":922},"engineering","2024-07-30","Learn how to create a GitLab CI/CD pipeline for a monorepo to host multiple applications in one repository.","md",null,false,"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749660151/Blog/Hero%20Images/blog-image-template-1800x945__26_.png",{},"/en-us/blog/building-a-gitlab-ci-cd-pipeline-for-a-monorepo-the-easy-way",{"title":5,"description":953,"ogTitle":5,"ogDescription":953,"noIndex":956,"ogImage":957,"ogUrl":961,"ogSiteName":962,"ogType":963,"canonicalUrls":961},"https://about.gitlab.com/blog/building-a-gitlab-ci-cd-pipeline-for-a-monorepo-the-easy-way","https://about.gitlab.com","article","building-a-gitlab-ci-cd-pipeline-for-a-monorepo-the-easy-way","en-us/blog/building-a-gitlab-ci-cd-pipeline-for-a-monorepo-the-easy-way",[20,967],"tutorial","BlogPost","sYv5AAxI80zCMlADP93ae0FQHinCCcHZRWNJORViJ5c",{"logo":971,"freeTrial":976,"sales":981,"login":986,"items":991,"search":1317,"minimal":1348,"duo":1367,"switchNav":1376,"pricingDeployment":1387},{"config":972},{"href":973,"dataGaName":974,"dataGaLocation":975},"/","gitlab logo","header",{"text":977,"config":978},"Get free trial",{"href":979,"dataGaName":980,"dataGaLocation":975},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com&glm_content=default-saas-trial/","free trial",{"text":982,"config":983},"Request a demo",{"href":984,"dataGaName":985,"dataGaLocation":975},"/sales/?contact-topic=request-demo","sales",{"text":987,"config":988},"Sign in",{"href":989,"dataGaName":990,"dataGaLocation":975},"https://gitlab.com/users/sign_in/","sign in",[992,1021,1120,1125,1239,1295],{"text":993,"config":994,"menu":996},"Platform",{"dataNavLevelOne":995},"platform",{"type":997,"columns":998},"cards",[999,1005,1013],{"title":993,"description":1000,"link":1001},"The intelligent orchestration platform for DevSecOps",{"text":1002,"config":1003},"Explore our Platform",{"href":1004,"dataGaName":995,"dataGaLocation":975},"/platform/",{"title":1006,"description":1007,"link":1008},"GitLab Duo Agent Platform","Agentic AI for the entire software lifecycle",{"text":1009,"config":1010},"Meet GitLab Duo",{"href":1011,"dataGaName":1012,"dataGaLocation":975},"/gitlab-duo-agent-platform/","gitlab duo agent platform",{"title":1014,"description":1015,"link":1016},"Why GitLab","See the top reasons enterprises choose GitLab",{"text":1017,"config":1018},"Learn more",{"href":1019,"dataGaName":1020,"dataGaLocation":975},"/why-gitlab/","why gitlab",{"text":1022,"left":117,"config":1023,"menu":1025},"Product",{"dataNavLevelOne":1024},"solutions",{"type":1026,"link":1027,"columns":1031,"feature":1099},"lists",{"text":1028,"config":1029},"View all Solutions",{"href":1030,"dataGaName":1024,"dataGaLocation":975},"/solutions/",[1032,1055,1078],{"title":1033,"description":1034,"link":1035,"items":1040},"Automation","CI/CD and automation to accelerate deployment",{"config":1036},{"icon":1037,"href":1038,"dataGaName":1039,"dataGaLocation":975},"AutomatedCodeAlt","/solutions/delivery-automation/","automated software delivery",[1041,1044,1047,1051],{"text":20,"config":1042},{"href":1043,"dataGaLocation":975,"dataGaName":20},"/solutions/continuous-integration/",{"text":1006,"config":1045},{"href":1011,"dataGaLocation":975,"dataGaName":1046},"gitlab duo agent platform - product menu",{"text":1048,"config":1049},"Source Code Management",{"href":1050,"dataGaLocation":975,"dataGaName":1048},"/solutions/source-code-management/",{"text":1052,"config":1053},"Automated Software Delivery",{"href":1038,"dataGaLocation":975,"dataGaName":1054},"Automated software delivery",{"title":1056,"description":1057,"link":1058,"items":1063},"Security","Deliver code faster without compromising security",{"config":1059},{"href":1060,"dataGaName":1061,"dataGaLocation":975,"icon":1062},"/solutions/application-security-testing/","security and compliance","ShieldCheckLight",[1064,1068,1073],{"text":1065,"config":1066},"Application Security Testing",{"href":1060,"dataGaName":1067,"dataGaLocation":975},"Application security testing",{"text":1069,"config":1070},"Software Supply Chain Security",{"href":1071,"dataGaLocation":975,"dataGaName":1072},"/solutions/supply-chain/","Software supply chain security",{"text":1074,"config":1075},"Software Compliance",{"href":1076,"dataGaName":1077,"dataGaLocation":975},"/solutions/software-compliance/","software compliance",{"title":1079,"link":1080,"items":1085},"Measurement",{"config":1081},{"icon":1082,"href":1083,"dataGaName":1084,"dataGaLocation":975},"DigitalTransformation","/solutions/visibility-measurement/","visibility and measurement",[1086,1090,1094],{"text":1087,"config":1088},"Visibility & Measurement",{"href":1083,"dataGaLocation":975,"dataGaName":1089},"Visibility and Measurement",{"text":1091,"config":1092},"Value Stream Management",{"href":1093,"dataGaLocation":975,"dataGaName":1091},"/solutions/value-stream-management/",{"text":1095,"config":1096},"Analytics & Insights",{"href":1097,"dataGaLocation":975,"dataGaName":1098},"/solutions/analytics-and-insights/","Analytics and insights",{"title":1100,"type":1026,"items":1101},"GitLab for",[1102,1108,1114],{"text":1103,"config":1104},"Enterprise",{"icon":1105,"href":1106,"dataGaLocation":975,"dataGaName":1107},"Building","/enterprise/","enterprise",{"text":1109,"config":1110},"Small Business",{"icon":1111,"href":1112,"dataGaLocation":975,"dataGaName":1113},"Work","/small-business/","small business",{"text":1115,"config":1116},"Public Sector",{"icon":1117,"href":1118,"dataGaLocation":975,"dataGaName":1119},"Organization","/solutions/public-sector/","public sector",{"text":1121,"config":1122},"Pricing",{"href":1123,"dataGaName":1124,"dataGaLocation":975,"dataNavLevelOne":1124},"/pricing/","pricing",{"text":1126,"config":1127,"menu":1129},"Resources",{"dataNavLevelOne":1128},"resources",{"type":1026,"link":1130,"columns":1134,"feature":1228},{"text":1131,"config":1132},"View all resources",{"href":1133,"dataGaName":1128,"dataGaLocation":975},"/resources/",[1135,1168,1195],{"title":1136,"items":1137},"Getting started",[1138,1143,1148,1153,1158,1163],{"text":1139,"config":1140},"Install",{"href":1141,"dataGaName":1142,"dataGaLocation":975},"/install/","install",{"text":1144,"config":1145},"Quick start guides",{"href":1146,"dataGaName":1147,"dataGaLocation":975},"/get-started/","quick setup checklists",{"text":1149,"config":1150},"Learn",{"href":1151,"dataGaLocation":975,"dataGaName":1152},"https://university.gitlab.com/","learn",{"text":1154,"config":1155},"Product documentation",{"href":1156,"dataGaName":1157,"dataGaLocation":975},"https://docs.gitlab.com/","product documentation",{"text":1159,"config":1160},"Best practice videos",{"href":1161,"dataGaName":1162,"dataGaLocation":975},"/getting-started-videos/","best practice videos",{"text":1164,"config":1165},"Integrations",{"href":1166,"dataGaName":1167,"dataGaLocation":975},"/integrations/","integrations",{"title":1169,"items":1170},"Discover",[1171,1176,1181,1186,1190],{"text":1172,"config":1173},"Customer success stories",{"href":1174,"dataGaName":1175,"dataGaLocation":975},"/customers/","customer success stories",{"text":1177,"config":1178},"Blog",{"href":1179,"dataGaName":1180,"dataGaLocation":975},"/blog/","blog",{"text":1182,"config":1183},"Demo Hub",{"href":1184,"dataGaName":1185,"dataGaLocation":975},"/demo-hub/","demo hub",{"text":1187,"config":1188},"The Source",{"href":1189,"dataGaName":1180,"dataGaLocation":975},"/the-source/",{"text":1191,"config":1192},"Remote",{"href":1193,"dataGaName":1194,"dataGaLocation":975},"https://handbook.gitlab.com/handbook/company/culture/all-remote/","remote",{"title":1196,"items":1197},"Connect",[1198,1203,1208,1213,1218,1223],{"text":1199,"config":1200},"GitLab Services",{"href":1201,"dataGaName":1202,"dataGaLocation":975},"/services/","services",{"text":1204,"config":1205},"Contribute",{"href":1206,"dataGaName":1207,"dataGaLocation":975},"https://contributors.gitlab.com","contribute",{"text":1209,"config":1210},"Community",{"href":1211,"dataGaName":1212,"dataGaLocation":975},"/community/","community",{"text":1214,"config":1215},"Forum",{"href":1216,"dataGaName":1217,"dataGaLocation":975},"https://forum.gitlab.com/","forum",{"text":1219,"config":1220},"Events",{"href":1221,"dataGaName":1222,"dataGaLocation":975},"/events/","events",{"text":1224,"config":1225},"Partners",{"href":1226,"dataGaName":1227,"dataGaLocation":975},"/partners/","partners",{"config":1229,"title":1232,"text":1233,"link":1234},{"background":1230,"textColor":1231},"url('https://res.cloudinary.com/about-gitlab-com/image/upload/v1777322348/qpq8yrgn8knii57omj0c.png')","#000","What’s new in GitLab","Stay updated with our latest features and improvements.",{"text":1235,"config":1236},"Read the latest",{"href":1237,"dataGaName":1238,"dataGaLocation":975},"/whats-new/","whats new",{"text":1240,"config":1241,"menu":1243},"Company",{"dataNavLevelOne":1242},"company",{"type":1026,"columns":1244},[1245],{"items":1246},[1247,1252,1258,1260,1265,1270,1275,1280,1285,1290],{"text":1248,"config":1249},"About",{"href":1250,"dataGaName":1251,"dataGaLocation":975},"/company/","about",{"text":1253,"config":1254,"footerGa":1257},"Jobs",{"href":1255,"dataGaName":1256,"dataGaLocation":975},"/jobs/","jobs",{"dataGaName":1256},{"text":1219,"config":1259},{"href":1221,"dataGaName":1222,"dataGaLocation":975},{"text":1261,"config":1262},"Leadership",{"href":1263,"dataGaName":1264,"dataGaLocation":975},"/company/team/e-group/","leadership",{"text":1266,"config":1267},"Handbook",{"href":1268,"dataGaName":1269,"dataGaLocation":975},"https://handbook.gitlab.com/","handbook",{"text":1271,"config":1272},"Investor relations",{"href":1273,"dataGaName":1274,"dataGaLocation":975},"https://ir.gitlab.com/overview/default.aspx","investor relations",{"text":1276,"config":1277},"Trust Center",{"href":1278,"dataGaName":1279,"dataGaLocation":975},"/security/","trust center",{"text":1281,"config":1282},"AI Transparency Center",{"href":1283,"dataGaName":1284,"dataGaLocation":975},"/ai-transparency-center/","ai transparency center",{"text":1286,"config":1287},"Newsletter",{"href":1288,"dataGaName":1289,"dataGaLocation":975},"/company/contact/#contact-forms","newsletter",{"text":1291,"config":1292},"Press",{"href":1293,"dataGaName":1294,"dataGaLocation":975},"/press/","press",{"text":1296,"config":1297,"menu":1298},"Contact us",{"dataNavLevelOne":1242},{"type":1026,"columns":1299},[1300],{"items":1301},[1302,1307,1312],{"text":1303,"config":1304},"Talk to sales",{"href":1305,"dataGaName":1306,"dataGaLocation":975},"/sales/","talk to sales",{"text":1308,"config":1309},"Support portal",{"href":1310,"dataGaName":1311,"dataGaLocation":975},"https://support.gitlab.com/hc/en-us","support portal",{"text":1313,"config":1314},"Customer portal",{"href":1315,"dataGaName":1316,"dataGaLocation":975},"https://customers.gitlab.com/customers/sign_in/","customer portal",{"close":1318,"login":1319,"suggestions":1326},"Close",{"text":1320,"link":1321},"To search repositories and projects, login to",{"text":1322,"config":1323},"gitlab.com",{"href":989,"dataGaName":1324,"dataGaLocation":1325},"search login","search",{"text":1327,"default":1328},"Suggestions",[1329,1331,1335,1337,1341,1345],{"text":1006,"config":1330},{"href":1011,"dataGaName":1006,"dataGaLocation":1325},{"text":1332,"config":1333},"Code Suggestions (AI)",{"href":1334,"dataGaName":1332,"dataGaLocation":1325},"/solutions/code-suggestions/",{"text":20,"config":1336},{"href":1043,"dataGaName":20,"dataGaLocation":1325},{"text":1338,"config":1339},"GitLab on AWS",{"href":1340,"dataGaName":1338,"dataGaLocation":1325},"/partners/technology-partners/aws/",{"text":1342,"config":1343},"GitLab on Google Cloud",{"href":1344,"dataGaName":1342,"dataGaLocation":1325},"/partners/technology-partners/google-cloud-platform/",{"text":1346,"config":1347},"Why GitLab?",{"href":1019,"dataGaName":1346,"dataGaLocation":1325},{"freeTrial":1349,"mobileIcon":1354,"desktopIcon":1359,"secondaryButton":1362},{"text":1350,"config":1351},"Start free trial",{"href":1352,"dataGaName":980,"dataGaLocation":1353},"https://gitlab.com/-/trials/new/","nav",{"altText":1355,"config":1356},"Gitlab Icon",{"src":1357,"dataGaName":1358,"dataGaLocation":1353},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203874/jypbw1jx72aexsoohd7x.svg","gitlab icon",{"altText":1355,"config":1360},{"src":1361,"dataGaName":1358,"dataGaLocation":1353},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203875/gs4c8p8opsgvflgkswz9.svg",{"text":1363,"config":1364},"Get Started",{"href":1365,"dataGaName":1366,"dataGaLocation":1353},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com/get-started/","get started",{"freeTrial":1368,"mobileIcon":1372,"desktopIcon":1374},{"text":1369,"config":1370},"Learn more about GitLab Duo",{"href":1011,"dataGaName":1371,"dataGaLocation":1353},"gitlab duo",{"altText":1355,"config":1373},{"src":1357,"dataGaName":1358,"dataGaLocation":1353},{"altText":1355,"config":1375},{"src":1361,"dataGaName":1358,"dataGaLocation":1353},{"button":1377,"mobileIcon":1382,"desktopIcon":1384},{"text":1378,"config":1379},"/switch",{"href":1380,"dataGaName":1381,"dataGaLocation":1353},"#contact","switch",{"altText":1355,"config":1383},{"src":1357,"dataGaName":1358,"dataGaLocation":1353},{"altText":1355,"config":1385},{"src":1386,"dataGaName":1358,"dataGaLocation":1353},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1773335277/ohhpiuoxoldryzrnhfrh.png",{"freeTrial":1388,"mobileIcon":1393,"desktopIcon":1395},{"text":1389,"config":1390},"Back to pricing",{"href":1123,"dataGaName":1391,"dataGaLocation":1353,"icon":1392},"back to pricing","GoBack",{"altText":1355,"config":1394},{"src":1357,"dataGaName":1358,"dataGaLocation":1353},{"altText":1355,"config":1396},{"src":1361,"dataGaName":1358,"dataGaLocation":1353},{"title":1398,"titleMobile":1399,"button":1400,"config":1405},"Duo Agent Platform delivers 400% ROI, per new Forrester Consulting study.","400% ROI: Forrester TEI for GitLab Duo",{"text":1017,"config":1401},{"href":1402,"dataGaName":1403,"dataGaLocation":1404},"https://about.gitlab.com/blog/gitlab-duo-agent-platform-delivers-400-percent-roi/","forrester-tei-dap-banner","global-banner",{"layout":1406,"disabled":956},"release",{"data":1408},{"text":1409,"source":1410,"edit":1416,"contribute":1421,"config":1426,"items":1431,"minimal":1641},"Git is a trademark of Software Freedom Conservancy and our use of 'GitLab' is under license",{"text":1411,"config":1412},"View page source",{"href":1413,"dataGaName":1414,"dataGaLocation":1415},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/","page source","footer",{"text":1417,"config":1418},"Edit this page",{"href":1419,"dataGaName":1420,"dataGaLocation":1415},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/content/","web ide",{"text":1422,"config":1423},"Please contribute",{"href":1424,"dataGaName":1425,"dataGaLocation":1415},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/CONTRIBUTING.md/","please contribute",{"twitter":1427,"facebook":1428,"youtube":1429,"linkedin":1430},"https://twitter.com/gitlab","https://www.facebook.com/gitlab","https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg","https://www.linkedin.com/company/gitlab-com",[1432,1479,1533,1577,1609],{"title":1121,"links":1433,"subMenu":1448},[1434,1438,1443],{"text":1435,"config":1436},"View plans",{"href":1123,"dataGaName":1437,"dataGaLocation":1415},"view plans",{"text":1439,"config":1440},"Why Premium?",{"href":1441,"dataGaName":1442,"dataGaLocation":1415},"/pricing/premium/","why premium",{"text":1444,"config":1445},"Why Ultimate?",{"href":1446,"dataGaName":1447,"dataGaLocation":1415},"/pricing/ultimate/","why ultimate",[1449],{"title":1450,"links":1451},"Contact Us",[1452,1455,1457,1459,1464,1469,1474],{"text":1453,"config":1454},"Contact sales",{"href":1305,"dataGaName":985,"dataGaLocation":1415},{"text":1308,"config":1456},{"href":1310,"dataGaName":1311,"dataGaLocation":1415},{"text":1313,"config":1458},{"href":1315,"dataGaName":1316,"dataGaLocation":1415},{"text":1460,"config":1461},"Status",{"href":1462,"dataGaName":1463,"dataGaLocation":1415},"https://status.gitlab.com/","status",{"text":1465,"config":1466},"Terms of use",{"href":1467,"dataGaName":1468,"dataGaLocation":1415},"/terms/","terms of use",{"text":1470,"config":1471},"Privacy statement",{"href":1472,"dataGaName":1473,"dataGaLocation":1415},"/privacy/","privacy statement",{"text":1475,"config":1476},"Cookie preferences",{"dataGaName":1477,"dataGaLocation":1415,"id":1478,"isOneTrustButton":117},"cookie preferences","ot-sdk-btn",{"title":1022,"links":1480,"subMenu":1489},[1481,1485],{"text":1482,"config":1483},"DevSecOps platform",{"href":1004,"dataGaName":1484,"dataGaLocation":1415},"devsecops platform",{"text":1486,"config":1487},"AI-Assisted Development",{"href":1011,"dataGaName":1488,"dataGaLocation":1415},"ai-assisted development",[1490],{"title":1491,"links":1492},"Topics",[1493,1498,1503,1508,1513,1518,1523,1528],{"text":1494,"config":1495},"CICD",{"href":1496,"dataGaName":1497,"dataGaLocation":1415},"/topics/ci-cd/","cicd",{"text":1499,"config":1500},"GitOps",{"href":1501,"dataGaName":1502,"dataGaLocation":1415},"/topics/gitops/","gitops",{"text":1504,"config":1505},"DevOps",{"href":1506,"dataGaName":1507,"dataGaLocation":1415},"/topics/devops/","devops",{"text":1509,"config":1510},"Version Control",{"href":1511,"dataGaName":1512,"dataGaLocation":1415},"/topics/version-control/","version control",{"text":1514,"config":1515},"DevSecOps",{"href":1516,"dataGaName":1517,"dataGaLocation":1415},"/topics/devsecops/","devsecops",{"text":1519,"config":1520},"Cloud Native",{"href":1521,"dataGaName":1522,"dataGaLocation":1415},"/topics/cloud-native/","cloud native",{"text":1524,"config":1525},"AI for Coding",{"href":1526,"dataGaName":1527,"dataGaLocation":1415},"/topics/devops/ai-for-coding/","ai for coding",{"text":1529,"config":1530},"Agentic AI",{"href":1531,"dataGaName":1532,"dataGaLocation":1415},"/topics/agentic-ai/","agentic ai",{"title":1534,"links":1535},"Solutions",[1536,1538,1540,1545,1549,1552,1556,1559,1561,1564,1567,1572],{"text":1065,"config":1537},{"href":1060,"dataGaName":1065,"dataGaLocation":1415},{"text":1054,"config":1539},{"href":1038,"dataGaName":1039,"dataGaLocation":1415},{"text":1541,"config":1542},"Agile development",{"href":1543,"dataGaName":1544,"dataGaLocation":1415},"/solutions/agile-delivery/","agile delivery",{"text":1546,"config":1547},"SCM",{"href":1050,"dataGaName":1548,"dataGaLocation":1415},"source code management",{"text":1494,"config":1550},{"href":1043,"dataGaName":1551,"dataGaLocation":1415},"continuous integration & delivery",{"text":1553,"config":1554},"Value stream management",{"href":1093,"dataGaName":1555,"dataGaLocation":1415},"value stream management",{"text":1499,"config":1557},{"href":1558,"dataGaName":1502,"dataGaLocation":1415},"/solutions/gitops/",{"text":1103,"config":1560},{"href":1106,"dataGaName":1107,"dataGaLocation":1415},{"text":1562,"config":1563},"Small business",{"href":1112,"dataGaName":1113,"dataGaLocation":1415},{"text":1565,"config":1566},"Public sector",{"href":1118,"dataGaName":1119,"dataGaLocation":1415},{"text":1568,"config":1569},"Education",{"href":1570,"dataGaName":1571,"dataGaLocation":1415},"/solutions/education/","education",{"text":1573,"config":1574},"Financial services",{"href":1575,"dataGaName":1576,"dataGaLocation":1415},"/solutions/finance/","financial services",{"title":1126,"links":1578},[1579,1581,1583,1585,1588,1590,1593,1595,1597,1599,1601,1603,1605,1607],{"text":1139,"config":1580},{"href":1141,"dataGaName":1142,"dataGaLocation":1415},{"text":1144,"config":1582},{"href":1146,"dataGaName":1147,"dataGaLocation":1415},{"text":1149,"config":1584},{"href":1151,"dataGaName":1152,"dataGaLocation":1415},{"text":1154,"config":1586},{"href":1156,"dataGaName":1587,"dataGaLocation":1415},"docs",{"text":1177,"config":1589},{"href":1179,"dataGaName":1180,"dataGaLocation":1415},{"text":1591,"config":1592},"What's new",{"href":1237,"dataGaName":1238,"dataGaLocation":1415},{"text":1172,"config":1594},{"href":1174,"dataGaName":1175,"dataGaLocation":1415},{"text":1191,"config":1596},{"href":1193,"dataGaName":1194,"dataGaLocation":1415},{"text":1199,"config":1598},{"href":1201,"dataGaName":1202,"dataGaLocation":1415},{"text":1204,"config":1600},{"href":1206,"dataGaName":1207,"dataGaLocation":1415},{"text":1209,"config":1602},{"href":1211,"dataGaName":1212,"dataGaLocation":1415},{"text":1214,"config":1604},{"href":1216,"dataGaName":1217,"dataGaLocation":1415},{"text":1219,"config":1606},{"href":1221,"dataGaName":1222,"dataGaLocation":1415},{"text":1224,"config":1608},{"href":1226,"dataGaName":1227,"dataGaLocation":1415},{"title":1240,"links":1610},[1611,1613,1615,1617,1619,1621,1625,1630,1632,1634,1636],{"text":1248,"config":1612},{"href":1250,"dataGaName":1242,"dataGaLocation":1415},{"text":1253,"config":1614},{"href":1255,"dataGaName":1256,"dataGaLocation":1415},{"text":1261,"config":1616},{"href":1263,"dataGaName":1264,"dataGaLocation":1415},{"text":1266,"config":1618},{"href":1268,"dataGaName":1269,"dataGaLocation":1415},{"text":1271,"config":1620},{"href":1273,"dataGaName":1274,"dataGaLocation":1415},{"text":1622,"config":1623},"Sustainability",{"href":1624,"dataGaName":1622,"dataGaLocation":1415},"/sustainability/",{"text":1626,"config":1627},"Diversity, inclusion and belonging (DIB)",{"href":1628,"dataGaName":1629,"dataGaLocation":1415},"/diversity-inclusion-belonging/","Diversity, inclusion and belonging",{"text":1276,"config":1631},{"href":1278,"dataGaName":1279,"dataGaLocation":1415},{"text":1286,"config":1633},{"href":1288,"dataGaName":1289,"dataGaLocation":1415},{"text":1291,"config":1635},{"href":1293,"dataGaName":1294,"dataGaLocation":1415},{"text":1637,"config":1638},"Modern Slavery Transparency Statement",{"href":1639,"dataGaName":1640,"dataGaLocation":1415},"https://handbook.gitlab.com/handbook/legal/modern-slavery-act-transparency-statement/","modern slavery transparency statement",{"items":1642},[1643,1646,1649],{"text":1644,"config":1645},"Terms",{"href":1467,"dataGaName":1468,"dataGaLocation":1415},{"text":1647,"config":1648},"Cookies",{"dataGaName":1477,"dataGaLocation":1415,"id":1478,"isOneTrustButton":117},{"text":1650,"config":1651},"Privacy",{"href":1472,"dataGaName":1473,"dataGaLocation":1415},[1653],{"id":1654,"title":7,"body":955,"config":1655,"content":1657,"description":955,"extension":1661,"meta":1662,"navigation":117,"path":1663,"seo":1664,"stem":1665,"__hash__":1666},"blogAuthors/en-us/blog/authors/sam-morris.yml",{"template":1656},"BlogAuthor",{"name":7,"config":1658},{"headshot":1659,"ctfId":1660},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749660148/Blog/Author%20Headshots/sam_morris.png","6JTrhUIqSCU30Y9KZOaan8","yml",{},"/en-us/blog/authors/sam-morris",{},"en-us/blog/authors/sam-morris","DfL241G6FQ5wNU6XYJLCEQLvnWBnyKnAi3wCPxOqBzE",[1668,1677,1685],{"title":1669,"description":1670,"heroImage":1671,"category":951,"date":1672,"authors":1673,"slug":1676,"externalUrl":955},"Confidential AI for GitLab Self-Hosted","Give developers AI coding agents in GitLab Duo without source code leaving a hardware-encrypted boundary — no GPUs needed.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1773866173/vte9qh8rriznvyclhkes.png","2026-08-06",[1674,1675],"Mathias Ewald","Martin Paloncy, Edgeless Systems","confidential-ai-for-gitlab-self-hosted",{"title":1678,"description":1679,"heroImage":1680,"category":951,"date":1681,"authors":1682,"slug":1684,"externalUrl":955},"Green DevOps: Why carbon measurement belongs in your CI/CD pipeline","CI/CD pipelines have a hidden carbon cost. Here's why measuring it matters, and how you can get started with Eco CI and Carmen in GitLab.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1765809212/noh0mdfn9o94ry9ykura.png","2026-07-09",[1683],"Lysanne Pinto","green-devops-carbon-measurement-cicd-pipeline",{"title":1686,"description":1687,"heroImage":1688,"category":951,"date":1689,"authors":1690,"slug":1692,"externalUrl":955},"How to build CI/CD observability at scale","This practical guide to GitLab pipeline analytics helps self-managed users gain operational insights using Prometheus and Grafana.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1774465167/n5hlvrsrheadeccyr1oz.png","2026-04-28",[1691],"Paul Meresanu","how-to-build-ci-cd-observability-at-scale",{"promotions":1694},[1695,1709,1721,1733],{"id":1696,"categories":1697,"header":1699,"text":1700,"button":1701,"image":1706},"ai-modernization",[1698],"ai","Is AI achieving its promise at scale?","Quiz will take 5 minutes or less",{"text":1702,"config":1703},"Get your AI maturity score",{"href":1704,"dataGaName":1705,"dataGaLocation":1180},"/assessments/ai-modernization-assessment/","modernization assessment",{"config":1707},{"src":1708},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/qix0m7kwnd8x2fh1zq49.png",{"id":1710,"categories":1711,"header":1713,"text":1700,"button":1714,"image":1718},"devops-modernization",[1712,1517],"product","Are you just managing tools or shipping innovation?",{"text":1715,"config":1716},"Get your DevOps maturity score",{"href":1717,"dataGaName":1705,"dataGaLocation":1180},"/assessments/devops-modernization-assessment/",{"config":1719},{"src":1720},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138785/eg818fmakweyuznttgid.png",{"id":1722,"categories":1723,"header":1725,"text":1700,"button":1726,"image":1730},"security-modernization",[1724],"security","Are you trading speed for security?",{"text":1727,"config":1728},"Get your security maturity score",{"href":1729,"dataGaName":1705,"dataGaLocation":1180},"/assessments/security-modernization-assessment/",{"config":1731},{"src":1732},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/p4pbqd9nnjejg5ds6mdk.png",{"id":1734,"paths":1735,"header":1738,"text":1739,"button":1740,"image":1745},"github-azure-migration",[1736,1737],"migration-from-azure-devops-to-gitlab","integrating-azure-devops-scm-and-gitlab","Is your team ready for GitHub's Azure move?","GitHub is already rebuilding around Azure. Find out what it means for you.",{"text":1741,"config":1742},"See how GitLab compares to GitHub",{"href":1743,"dataGaName":1744,"dataGaLocation":1180},"/compare/gitlab-vs-github/github-azure-migration/","github azure migration",{"config":1746},{"src":1720},{"header":1748,"blurb":1749,"button":1750,"secondaryButton":1755},"Start building faster today","See what your team can do with the intelligent orchestration platform for DevSecOps.\n",{"text":1751,"config":1752},"Get your free trial",{"href":1753,"dataGaName":980,"dataGaLocation":1754},"https://gitlab.com/-/trial_registrations/new?glm_content=default-saas-trial&glm_source=about.gitlab.com/","feature",{"text":1453,"config":1756},{"href":1305,"dataGaName":985,"dataGaLocation":1754},1786803747872]