[{"data":1,"prerenderedAt":1546},["ShallowReactive",2],{"/blog/parent-child-vs-multi-project-pipelines":3,"navigation-en-us":759,"banner-en-us":1187,"footer-en-us":1197,"blog-post-authors-en-us-Fabio Pitino":1441,"blog-related-posts-en-us-parent-child-vs-multi-project-pipelines":1456,"blog-promotions-en-us":1482,"next-steps-en-us":1536},{"id":4,"title":5,"authors":6,"body":8,"category":737,"date":738,"description":739,"extension":740,"externalUrl":741,"faq":741,"featured":742,"heroImage":743,"meta":744,"navigation":365,"path":745,"seo":746,"slug":751,"stem":752,"tags":753,"template":757,"updatedDate":741,"__hash__":758},"blogPosts/en-us/blog/parent-child-vs-multi-project-pipelines.md","Breaking down CI/CD complexity with parent-child and multi-project pipelines",[7],"Fabio Pitino",{"type":9,"value":10,"toc":731},"minimark",[11,15,18,21,38,41,56,64,67,72,75,101,107,110,125,258,268,271,278,297,307,310,314,321,324,327,330,435,442,559,565,568,578,582,585,588,601,604,625,628,669,672,680,684,687,690,704,713,727],[12,13,14],"p",{},"Software requirements change over time. Customers request more features and the application needs to scale well\nto meet user demands. As software grows in size, so does its complexity, to the point where we might decide that it's\ntime to split the project up into smaller, cohesive components.",[12,16,17],{},"As we proceed to tackle this complexity we want to ensure that our CI/CD pipelines continue to validate\nthat all the pieces work correctly together.",[12,19,20],{},"There are two typical paths to splitting up software projects:",[22,23,24,32],"ul",{},[25,26,27,31],"li",{},[28,29,30],"strong",{},"Isolating independent modules within the same repository",": For example, separating the UI from the backend,\nthe documentation from code, or extracting code into independent packages.",[25,33,34,37],{},[28,35,36],{},"Extracting code into a separate repository",": For example, extracting some generic logic into a library, or creating\nindependent microservices.",[12,39,40],{},"When we pick a path for splitting up the project, we should also adapt the CI/CD pipeline to match.",[12,42,43,44,49,50,55],{},"For the first path, ",[45,46,48],"a",{"href":47},"/topics/ci-cd/","GitLab CI/CD"," provides ",[45,51,54],{"href":52,"rel":53},"https://docs.gitlab.com/ci/pipelines/downstream_pipelines/",[],"parent-child pipelines"," as a feature that helps manage complexity while keeping it all in a monorepo.",[12,57,58,59,63],{},"For the second path, ",[45,60,62],{"href":52,"rel":61},[],"multi-project pipelines","\nare the glue that helps ensure multiple separate repositories work together.",[12,65,66],{},"Let's look into how these two approaches differ, and understand how to best leverage them.",[68,69,71],"h2",{"id":70},"parent-child-pipelines","Parent-child pipelines",[12,73,74],{},"It can be challenging to maintain complex CI/CD pipeline configurations, especially when you need to coordinate many jobs that may relate\nto different components, while at the same time keeping the pipeline efficient.",[12,76,77,78,82,83,86,87,90,91,93,94,97,98,100],{},"Let's imagine we have an app with all code in the same repository, but split into UI and backend components. A \"one-size-fits-all\" pipeline for this app probably would have all the jobs grouped into common stages that cover all the components. The default is to use ",[79,80,81],"code",{},"build",", ",[79,84,85],{},"test",", and ",[79,88,89],{},"deploy"," stages.\nUnfortunately, this could be a source of inefficiency because the UI and backend represent two separate tracks of the pipeline.\nThey each have their own independent requirements and structure and likely don't depend on each other.\nThe UI might not need the ",[79,92,81],{}," stage at all, but it might instead need a ",[79,95,96],{},"system-test"," stage with jobs that test the app end-to-end.\nSimilarly, the UI jobs from ",[79,99,96],{}," might not need to wait for backend jobs to complete.",[12,102,103,106],{},[45,104,71],{"href":52,"rel":105},[]," help here,\nenabling you to extract cohesive parts of the pipeline into child pipelines that runs in isolation.",[12,108,109],{},"With parent-child pipelines we could break the configurations down into two separate\ntracks by having two separate jobs trigger child pipelines:",[22,111,112,119],{},[25,113,114,115,118],{},"The ",[79,116,117],{},"ui"," job triggers a child pipeline that runs all the UI jobs.",[25,120,114,121,124],{},[79,122,123],{},"backend"," job triggers a separate child pipeline that runs all the backend jobs.",[126,127,132],"pre",{"className":128,"code":129,"language":130,"meta":131,"style":131},"language-yaml shiki shiki-themes github-light","ui:\n  trigger:\n    include: ui/.gitlab-ci.yml\n    strategy: depend\n  rules:\n    - changes: [ui/*]\nbackend:\n  trigger:\n    include: backend/.gitlab-ci.yml\n    strategy: depend\n  rules:\n    - changes: [backend/*]\n\n","yaml","",[79,133,134,146,154,167,178,186,204,211,218,228,237,244],{"__ignoreMap":131},[135,136,139,142],"span",{"class":137,"line":138},"line",1,[135,140,117],{"class":141},"shJU0",[135,143,145],{"class":144},"sgsFI",":\n",[135,147,149,152],{"class":137,"line":148},2,[135,150,151],{"class":141},"  trigger",[135,153,145],{"class":144},[135,155,157,160,163],{"class":137,"line":156},3,[135,158,159],{"class":141},"    include",[135,161,162],{"class":144},": ",[135,164,166],{"class":165},"sYBdl","ui/.gitlab-ci.yml\n",[135,168,170,173,175],{"class":137,"line":169},4,[135,171,172],{"class":141},"    strategy",[135,174,162],{"class":144},[135,176,177],{"class":165},"depend\n",[135,179,181,184],{"class":137,"line":180},5,[135,182,183],{"class":141},"  rules",[135,185,145],{"class":144},[135,187,189,192,195,198,201],{"class":137,"line":188},6,[135,190,191],{"class":144},"    - ",[135,193,194],{"class":141},"changes",[135,196,197],{"class":144},": [",[135,199,200],{"class":165},"ui/*",[135,202,203],{"class":144},"]\n",[135,205,207,209],{"class":137,"line":206},7,[135,208,123],{"class":141},[135,210,145],{"class":144},[135,212,214,216],{"class":137,"line":213},8,[135,215,151],{"class":141},[135,217,145],{"class":144},[135,219,221,223,225],{"class":137,"line":220},9,[135,222,159],{"class":141},[135,224,162],{"class":144},[135,226,227],{"class":165},"backend/.gitlab-ci.yml\n",[135,229,231,233,235],{"class":137,"line":230},10,[135,232,172],{"class":141},[135,234,162],{"class":144},[135,236,177],{"class":165},[135,238,240,242],{"class":137,"line":239},11,[135,241,183],{"class":141},[135,243,145],{"class":144},[135,245,247,249,251,253,256],{"class":137,"line":246},12,[135,248,191],{"class":144},[135,250,194],{"class":141},[135,252,197],{"class":144},[135,254,255],{"class":165},"backend/*",[135,257,203],{"class":144},[12,259,260,261,264,265,267],{},"The modifier ",[79,262,263],{},"strategy: depend",", which is also available for multi-project pipelines, makes the trigger job reflect the status of the\ndownstream (child) pipeline and waits for it to complete. Without ",[79,266,263],{}," the trigger job succeeds immediately after creating the downstream pipeline.",[12,269,270],{},"Now the frontend and backend teams can manage their CI/CD configurations without impacting each other's pipelines. In addition to that, we can now explicitly visualize the two workflows.",[12,272,273],{},[274,275],"img",{"alt":276,"src":277},"example parent-child pipeline","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782397707/blog/Content%20Images/2022-02-01-parent-child-vs-multi-project-pipelines/parent-child.png",[12,279,280,281,284,285,288,289,292,293,296],{},"The two pipelines run in isolation, so we can set variables or configuration in one without affecting the other. For example, we could use ",[79,282,283],{},"rules:changes"," or ",[79,286,287],{},"workflow:rules"," inside ",[79,290,291],{},"backend/.gitlab-ci.yml",", but use something completely different in ",[79,294,295],{},"ui/.gitlab-ci.yml",".",[12,298,299,300,82,303,306],{},"Child pipelines run in the same context of the parent pipeline, which is the combination of project, Git ref and commit SHA. Additionally, the child pipeline inherits some information from the parent pipeline, including Git push data like ",[79,301,302],{},"before_sha",[79,304,305],{},"target_sha",", the related merge request, etc.\nHaving the same context ensures that the child pipeline can safely run as a sub-pipeline of the parent, but be in complete isolation.",[12,308,309],{},"A programming analogy to parent-child pipelines would be to break down long procedural code into smaller, single-purpose functions.",[68,311,313],{"id":312},"multi-project-pipelines","Multi-project pipelines",[12,315,316,317,320],{},"If our app spans across different repositories, we should instead leverage ",[45,318,62],{"href":52,"rel":319},[],". Each repository defines a pipeline that suits the project's needs. Then, these standalone and independent pipelines can be chained together to create essentially a much bigger pipeline that ensures all the projects are integrated correctly.",[12,322,323],{},"There can be endless possibilities and topologies, but let's explore a simple case of asking another project\nto run a service for our pipeline.",[12,325,326],{},"The app is divided into multiple repositories, each hosting an independent component of the app.\nWhen one of the components changes, that project's pipeline runs.\nIf the earlier jobs in the pipeline are successful, a final job triggers a pipeline on a different project, which is the project responsible for building, running smoke tests, and\ndeploying the whole app. If the component pipeline fails because of a bug, the process is interrupted and there is no\nneed to trigger a pipeline for the main app project.",[12,328,329],{},"The component project's pipeline:",[126,331,333],{"className":128,"code":332,"language":130,"meta":131,"style":131},"build:\n  stage: build\n  script: ./build_component.sh\n\ntest:\n  stage: test\n  script: ./test_component.sh\n\ndeploy:\n  stage: deploy\n  trigger:\n    project: myorg/app\n    strategy: depend\n\n",[79,334,335,341,351,361,367,373,382,391,395,401,410,416,426],{"__ignoreMap":131},[135,336,337,339],{"class":137,"line":138},[135,338,81],{"class":141},[135,340,145],{"class":144},[135,342,343,346,348],{"class":137,"line":148},[135,344,345],{"class":141},"  stage",[135,347,162],{"class":144},[135,349,350],{"class":165},"build\n",[135,352,353,356,358],{"class":137,"line":156},[135,354,355],{"class":141},"  script",[135,357,162],{"class":144},[135,359,360],{"class":165},"./build_component.sh\n",[135,362,363],{"class":137,"line":169},[135,364,366],{"emptyLinePlaceholder":365},true,"\n",[135,368,369,371],{"class":137,"line":180},[135,370,85],{"class":141},[135,372,145],{"class":144},[135,374,375,377,379],{"class":137,"line":188},[135,376,345],{"class":141},[135,378,162],{"class":144},[135,380,381],{"class":165},"test\n",[135,383,384,386,388],{"class":137,"line":206},[135,385,355],{"class":141},[135,387,162],{"class":144},[135,389,390],{"class":165},"./test_component.sh\n",[135,392,393],{"class":137,"line":213},[135,394,366],{"emptyLinePlaceholder":365},[135,396,397,399],{"class":137,"line":220},[135,398,89],{"class":141},[135,400,145],{"class":144},[135,402,403,405,407],{"class":137,"line":230},[135,404,345],{"class":141},[135,406,162],{"class":144},[135,408,409],{"class":165},"deploy\n",[135,411,412,414],{"class":137,"line":239},[135,413,151],{"class":141},[135,415,145],{"class":144},[135,417,418,421,423],{"class":137,"line":246},[135,419,420],{"class":141},"    project",[135,422,162],{"class":144},[135,424,425],{"class":165},"myorg/app\n",[135,427,429,431,433],{"class":137,"line":428},13,[135,430,172],{"class":141},[135,432,162],{"class":144},[135,434,177],{"class":165},[12,436,437,438,441],{},"The full app project's pipeline in ",[79,439,440],{},"myorg/app"," project:",[126,443,445],{"className":128,"code":444,"language":130,"meta":131,"style":131},"build:\n  stage: build\n  script: ./build_app.sh  # build all components\n\nqa-test:\n  stage: test\n  script: ./qa_test.sh\n\nsmoke-test:\n  stage: test\n  script: ./smoke_test.sh\n\ndeploy:\n  stage: deploy\n  script: ./deploy_app.sh\n\n",[79,446,447,453,461,474,478,485,493,502,506,513,521,530,534,540,549],{"__ignoreMap":131},[135,448,449,451],{"class":137,"line":138},[135,450,81],{"class":141},[135,452,145],{"class":144},[135,454,455,457,459],{"class":137,"line":148},[135,456,345],{"class":141},[135,458,162],{"class":144},[135,460,350],{"class":165},[135,462,463,465,467,470],{"class":137,"line":156},[135,464,355],{"class":141},[135,466,162],{"class":144},[135,468,469],{"class":165},"./build_app.sh",[135,471,473],{"class":472},"sAwPA","  # build all components\n",[135,475,476],{"class":137,"line":169},[135,477,366],{"emptyLinePlaceholder":365},[135,479,480,483],{"class":137,"line":180},[135,481,482],{"class":141},"qa-test",[135,484,145],{"class":144},[135,486,487,489,491],{"class":137,"line":188},[135,488,345],{"class":141},[135,490,162],{"class":144},[135,492,381],{"class":165},[135,494,495,497,499],{"class":137,"line":206},[135,496,355],{"class":141},[135,498,162],{"class":144},[135,500,501],{"class":165},"./qa_test.sh\n",[135,503,504],{"class":137,"line":213},[135,505,366],{"emptyLinePlaceholder":365},[135,507,508,511],{"class":137,"line":220},[135,509,510],{"class":141},"smoke-test",[135,512,145],{"class":144},[135,514,515,517,519],{"class":137,"line":230},[135,516,345],{"class":141},[135,518,162],{"class":144},[135,520,381],{"class":165},[135,522,523,525,527],{"class":137,"line":239},[135,524,355],{"class":141},[135,526,162],{"class":144},[135,528,529],{"class":165},"./smoke_test.sh\n",[135,531,532],{"class":137,"line":246},[135,533,366],{"emptyLinePlaceholder":365},[135,535,536,538],{"class":137,"line":428},[135,537,89],{"class":141},[135,539,145],{"class":144},[135,541,543,545,547],{"class":137,"line":542},14,[135,544,345],{"class":141},[135,546,162],{"class":144},[135,548,409],{"class":165},[135,550,552,554,556],{"class":137,"line":551},15,[135,553,355],{"class":141},[135,555,162],{"class":144},[135,557,558],{"class":165},"./deploy_app.sh\n",[12,560,561],{},[274,562],{"alt":563,"src":564},"example multi-project pipeline","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782397707/blog/Content%20Images/2022-02-01-parent-child-vs-multi-project-pipelines/multi-project.png",[12,566,567],{},"In our example, the component pipeline (upstream) triggers a downstream multi-project pipeline to perform a service:\nverify the components work together, then deploy the whole app.",[12,569,570,571,574,575,577],{},"A programming analogy to multi-project pipelines would be like calling an external component or function to\neither receive a service (using ",[79,572,573],{},"strategy:depend",") or to notify it that an event occurred (without ",[79,576,573],{},").",[68,579,581],{"id":580},"key-differences-between-parent-child-and-multi-project-pipelines","Key differences between parent-child and multi-project pipelines",[12,583,584],{},"As seen above, the most obvious difference between parent-child and multi-project pipelines is the project\nwhere the pipelines run, but there are are other differences to be aware of.",[12,586,587],{},"Context:",[22,589,590,593],{},[25,591,592],{},"Parent-child pipelines run on the same context: same project, ref, and commit SHA.",[25,594,595,596,600],{},"Multi-project pipelines run on completely separate contexts. The upstream multi-project pipeline can indicate ",[45,597,599],{"href":52,"rel":598},[],"a ref to use",", which can indicate what version of the pipeline to trigger.",[12,602,603],{},"Control:",[22,605,606,618],{},[25,607,608,609,613,614,296],{},"A parent pipeline ",[610,611,612],"em",{},"generates"," a child pipeline, and the parent can have a high degree of control over what the child pipeline\nruns. The parent can even ",[45,615,617],{"href":52,"rel":616},[],"dynamically generate configurations for child pipelines",[25,619,620,621,624],{},"An upstream pipeline ",[610,622,623],{},"triggers"," a downstream multi-project pipeline. The upstream (triggering) pipeline does not have much control over the structure of the downstream (triggered) pipeline.\nThe upstream project treats the downstream pipeline as a black box.\nIt can only choose the ref to use and pass some variables downstream.",[12,626,627],{},"Side-effects:",[22,629,630,657,663,666],{},[25,631,632,633,636,637,639,640,645,646,649,650,652,653,656],{},"The final status of a parent pipeline, like other normal pipelines, affects the status of the ref the pipeline runs against. For example, if a parent pipeline fails on the ",[79,634,635],{},"main"," branch, we say that ",[79,638,635],{}," is broken.\nThe status of a ref is used in various scenarios, including ",[45,641,644],{"href":642,"rel":643},"https://docs.gitlab.com/api/job_artifacts/#download-the-artifacts-archive",[],"downloading artifacts"," from the latest successful pipeline.",[647,648],"br",{},"Child pipelines, on the other hand, run on behalf of the parent pipeline, and they don't directly affect the ref status. If triggered using ",[79,651,263],{},", a child pipeline affects the status of the parent pipeline.\nIn turn, the parent pipeline can be configured to fail or succeed based on ",[79,654,655],{},"allow_failure:"," configuration on the job triggering the child pipeline.",[25,658,659,660,662],{},"A multi-project downstream pipeline may affect the status of the upstream pipeline if triggered using ",[79,661,263],{},",\nbut each downstream pipeline affects the status of the ref in the project they run.",[25,664,665],{},"Parent and child pipelines that are still running are all automatically canceled if interruptible when a new pipeline is created for the same ref.",[25,667,668],{},"Multi-project downstream pipelines are not automatically canceled when a new upstream pipeline runs for the same ref. The auto-cancelation feature only works within the same project.\nDownstream multi-project pipelines are considered \"external logic\". They can only be auto-canceled when configured to be interruptible\nand a new pipeline is triggered for the same ref on the downstream project (not the upstream project).",[12,670,671],{},"Visibility:",[22,673,674,677],{},[25,675,676],{},"Child pipelines are not directly visible in the pipelines index page because they are considered internal\nsub-components of the parent pipeline. This is to enforce the fact that child pipelines are not standalone and they are considered sub-components of the parent pipeline.\nChild pipelines are discoverable only through their parent pipeline page.",[25,678,679],{},"Multi-project pipelines are standalone pipelines because they are normal pipelines, but just happen to be triggered by an another project's pipeline. They are all visible in the pipeline index page.",[68,681,683],{"id":682},"conclusions","Conclusions",[12,685,686],{},"Parent-child pipelines inherit a lot of the design from multi-project pipelines, but parent-child pipelines have differences that make them a very unique type\nof pipeline relationship.",[12,688,689],{},"Some of the parent-child pipelines work we at GitLab will be focusing on is about surfacing job reports generated in child pipelines as merge request widgets,\ncascading cancelation and removal of pipelines as well as passing variables across related pipelines.\nSome of the parent-child pipeline work we at GitLab plan to focus on relates to:",[22,691,692,695,698,701],{},[25,693,694],{},"Surfacing job reports generated in child pipelines in merge request widgets.",[25,696,697],{},"Cascading cancelation down to child pipelines.",[25,699,700],{},"Cascading removal down to child pipelines.",[25,702,703],{},"Passing variables across related pipelines.",[12,705,706,707,712],{},"You can check ",[45,708,711],{"href":709,"rel":710},"https://gitlab.com/gitlab-org/gitlab/-/issues/336884",[],"this issue"," for planned future developments on parent-child and multi-project pipelines.\nLeave feedback or let us know how we can help.",[12,714,715,716,721,722],{},"Cover image by ",[45,717,720],{"href":718,"rel":719},"https://unsplash.com/@ravi_roshan_inc?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText",[],"Ravi Roshan"," on ",[45,723,726],{"href":724,"rel":725},"https://unsplash.com/?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText",[],"Unsplash",[728,729,730],"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);}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}",{"title":131,"searchDepth":148,"depth":148,"links":732},[733,734,735,736],{"id":70,"depth":148,"text":71},{"id":312,"depth":148,"text":313},{"id":580,"depth":148,"text":581},{"id":682,"depth":148,"text":683},"engineering","2022-02-22","Parent-child pipelines inherit a lot of the design from multi-project pipelines, but they also have differences that make them unique.","md",null,false,"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749659961/Blog/Hero%20Images/parent-child-multi-project-pipelines-unsplash.jpg",{},"/en-us/blog/parent-child-vs-multi-project-pipelines",{"title":747,"description":739,"ogTitle":747,"ogDescription":739,"noIndex":742,"ogImage":743,"ogUrl":748,"ogSiteName":749,"ogType":750,"canonicalUrls":748},"CI/CD patterns with parent-child and multi-project pipelines","https://about.gitlab.com/blog/parent-child-vs-multi-project-pipelines","https://about.gitlab.com","article","parent-child-vs-multi-project-pipelines","en-us/blog/parent-child-vs-multi-project-pipelines",[754,755,756],"CI","CD","features","BlogPost","V2qYxjMqDBUmCKtECl5ieWHaEJwiJrBhuRmhQOhl9xs",{"logo":760,"freeTrial":765,"sales":770,"login":775,"items":780,"search":1107,"minimal":1138,"duo":1157,"switchNav":1166,"pricingDeployment":1177},{"config":761},{"href":762,"dataGaName":763,"dataGaLocation":764},"/","gitlab logo","header",{"text":766,"config":767},"Get free trial",{"href":768,"dataGaName":769,"dataGaLocation":764},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com&glm_content=default-saas-trial/","free trial",{"text":771,"config":772},"Request a demo",{"href":773,"dataGaName":774,"dataGaLocation":764},"/sales/?contact-topic=request-demo","sales",{"text":776,"config":777},"Sign in",{"href":778,"dataGaName":779,"dataGaLocation":764},"https://gitlab.com/users/sign_in/","sign in",[781,810,910,915,1029,1085],{"text":782,"config":783,"menu":785},"Platform",{"dataNavLevelOne":784},"platform",{"type":786,"columns":787},"cards",[788,794,802],{"title":782,"description":789,"link":790},"The intelligent orchestration platform for DevSecOps",{"text":791,"config":792},"Explore our Platform",{"href":793,"dataGaName":784,"dataGaLocation":764},"/platform/",{"title":795,"description":796,"link":797},"GitLab Duo Agent Platform","Agentic AI for the entire software lifecycle",{"text":798,"config":799},"Meet GitLab Duo",{"href":800,"dataGaName":801,"dataGaLocation":764},"/gitlab-duo-agent-platform/","gitlab duo agent platform",{"title":803,"description":804,"link":805},"Why GitLab","See the top reasons enterprises choose GitLab",{"text":806,"config":807},"Learn more",{"href":808,"dataGaName":809,"dataGaLocation":764},"/why-gitlab/","why gitlab",{"text":811,"left":365,"config":812,"menu":814},"Product",{"dataNavLevelOne":813},"solutions",{"type":815,"link":816,"columns":820,"feature":889},"lists",{"text":817,"config":818},"View all Solutions",{"href":819,"dataGaName":813,"dataGaLocation":764},"/solutions/",[821,845,868],{"title":822,"description":823,"link":824,"items":829},"Automation","CI/CD and automation to accelerate deployment",{"config":825},{"icon":826,"href":827,"dataGaName":828,"dataGaLocation":764},"AutomatedCodeAlt","/solutions/delivery-automation/","automated software delivery",[830,834,837,841],{"text":831,"config":832},"CI/CD",{"href":833,"dataGaLocation":764,"dataGaName":831},"/solutions/continuous-integration/",{"text":795,"config":835},{"href":800,"dataGaLocation":764,"dataGaName":836},"gitlab duo agent platform - product menu",{"text":838,"config":839},"Source Code Management",{"href":840,"dataGaLocation":764,"dataGaName":838},"/solutions/source-code-management/",{"text":842,"config":843},"Automated Software Delivery",{"href":827,"dataGaLocation":764,"dataGaName":844},"Automated software delivery",{"title":846,"description":847,"link":848,"items":853},"Security","Deliver code faster without compromising security",{"config":849},{"href":850,"dataGaName":851,"dataGaLocation":764,"icon":852},"/solutions/application-security-testing/","security and compliance","ShieldCheckLight",[854,858,863],{"text":855,"config":856},"Application Security Testing",{"href":850,"dataGaName":857,"dataGaLocation":764},"Application security testing",{"text":859,"config":860},"Software Supply Chain Security",{"href":861,"dataGaLocation":764,"dataGaName":862},"/solutions/supply-chain/","Software supply chain security",{"text":864,"config":865},"Software Compliance",{"href":866,"dataGaName":867,"dataGaLocation":764},"/solutions/software-compliance/","software compliance",{"title":869,"link":870,"items":875},"Measurement",{"config":871},{"icon":872,"href":873,"dataGaName":874,"dataGaLocation":764},"DigitalTransformation","/solutions/visibility-measurement/","visibility and measurement",[876,880,884],{"text":877,"config":878},"Visibility & Measurement",{"href":873,"dataGaLocation":764,"dataGaName":879},"Visibility and Measurement",{"text":881,"config":882},"Value Stream Management",{"href":883,"dataGaLocation":764,"dataGaName":881},"/solutions/value-stream-management/",{"text":885,"config":886},"Analytics & Insights",{"href":887,"dataGaLocation":764,"dataGaName":888},"/solutions/analytics-and-insights/","Analytics and insights",{"title":890,"type":815,"items":891},"GitLab for",[892,898,904],{"text":893,"config":894},"Enterprise",{"icon":895,"href":896,"dataGaLocation":764,"dataGaName":897},"Building","/enterprise/","enterprise",{"text":899,"config":900},"Small Business",{"icon":901,"href":902,"dataGaLocation":764,"dataGaName":903},"Work","/small-business/","small business",{"text":905,"config":906},"Public Sector",{"icon":907,"href":908,"dataGaLocation":764,"dataGaName":909},"Organization","/solutions/public-sector/","public sector",{"text":911,"config":912},"Pricing",{"href":913,"dataGaName":914,"dataGaLocation":764,"dataNavLevelOne":914},"/pricing/","pricing",{"text":916,"config":917,"menu":919},"Resources",{"dataNavLevelOne":918},"resources",{"type":815,"link":920,"columns":924,"feature":1018},{"text":921,"config":922},"View all resources",{"href":923,"dataGaName":918,"dataGaLocation":764},"/resources/",[925,958,985],{"title":926,"items":927},"Getting started",[928,933,938,943,948,953],{"text":929,"config":930},"Install",{"href":931,"dataGaName":932,"dataGaLocation":764},"/install/","install",{"text":934,"config":935},"Quick start guides",{"href":936,"dataGaName":937,"dataGaLocation":764},"/get-started/","quick setup checklists",{"text":939,"config":940},"Learn",{"href":941,"dataGaLocation":764,"dataGaName":942},"https://university.gitlab.com/","learn",{"text":944,"config":945},"Product documentation",{"href":946,"dataGaName":947,"dataGaLocation":764},"https://docs.gitlab.com/","product documentation",{"text":949,"config":950},"Best practice videos",{"href":951,"dataGaName":952,"dataGaLocation":764},"/getting-started-videos/","best practice videos",{"text":954,"config":955},"Integrations",{"href":956,"dataGaName":957,"dataGaLocation":764},"/integrations/","integrations",{"title":959,"items":960},"Discover",[961,966,971,976,980],{"text":962,"config":963},"Customer success stories",{"href":964,"dataGaName":965,"dataGaLocation":764},"/customers/","customer success stories",{"text":967,"config":968},"Blog",{"href":969,"dataGaName":970,"dataGaLocation":764},"/blog/","blog",{"text":972,"config":973},"Demo Hub",{"href":974,"dataGaName":975,"dataGaLocation":764},"/demo-hub/","demo hub",{"text":977,"config":978},"The Source",{"href":979,"dataGaName":970,"dataGaLocation":764},"/the-source/",{"text":981,"config":982},"Remote",{"href":983,"dataGaName":984,"dataGaLocation":764},"https://handbook.gitlab.com/handbook/company/culture/all-remote/","remote",{"title":986,"items":987},"Connect",[988,993,998,1003,1008,1013],{"text":989,"config":990},"GitLab Services",{"href":991,"dataGaName":992,"dataGaLocation":764},"/services/","services",{"text":994,"config":995},"Contribute",{"href":996,"dataGaName":997,"dataGaLocation":764},"https://contributors.gitlab.com","contribute",{"text":999,"config":1000},"Community",{"href":1001,"dataGaName":1002,"dataGaLocation":764},"/community/","community",{"text":1004,"config":1005},"Forum",{"href":1006,"dataGaName":1007,"dataGaLocation":764},"https://forum.gitlab.com/","forum",{"text":1009,"config":1010},"Events",{"href":1011,"dataGaName":1012,"dataGaLocation":764},"/events/","events",{"text":1014,"config":1015},"Partners",{"href":1016,"dataGaName":1017,"dataGaLocation":764},"/partners/","partners",{"config":1019,"title":1022,"text":1023,"link":1024},{"background":1020,"textColor":1021},"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":1025,"config":1026},"Read the latest",{"href":1027,"dataGaName":1028,"dataGaLocation":764},"/whats-new/","whats new",{"text":1030,"config":1031,"menu":1033},"Company",{"dataNavLevelOne":1032},"company",{"type":815,"columns":1034},[1035],{"items":1036},[1037,1042,1048,1050,1055,1060,1065,1070,1075,1080],{"text":1038,"config":1039},"About",{"href":1040,"dataGaName":1041,"dataGaLocation":764},"/company/","about",{"text":1043,"config":1044,"footerGa":1047},"Jobs",{"href":1045,"dataGaName":1046,"dataGaLocation":764},"/jobs/","jobs",{"dataGaName":1046},{"text":1009,"config":1049},{"href":1011,"dataGaName":1012,"dataGaLocation":764},{"text":1051,"config":1052},"Leadership",{"href":1053,"dataGaName":1054,"dataGaLocation":764},"/company/team/e-group/","leadership",{"text":1056,"config":1057},"Handbook",{"href":1058,"dataGaName":1059,"dataGaLocation":764},"https://handbook.gitlab.com/","handbook",{"text":1061,"config":1062},"Investor relations",{"href":1063,"dataGaName":1064,"dataGaLocation":764},"https://ir.gitlab.com/overview/default.aspx","investor relations",{"text":1066,"config":1067},"Trust Center",{"href":1068,"dataGaName":1069,"dataGaLocation":764},"/security/","trust center",{"text":1071,"config":1072},"AI Transparency Center",{"href":1073,"dataGaName":1074,"dataGaLocation":764},"/ai-transparency-center/","ai transparency center",{"text":1076,"config":1077},"Newsletter",{"href":1078,"dataGaName":1079,"dataGaLocation":764},"/company/contact/#contact-forms","newsletter",{"text":1081,"config":1082},"Press",{"href":1083,"dataGaName":1084,"dataGaLocation":764},"/press/","press",{"text":1086,"config":1087,"menu":1088},"Contact us",{"dataNavLevelOne":1032},{"type":815,"columns":1089},[1090],{"items":1091},[1092,1097,1102],{"text":1093,"config":1094},"Talk to sales",{"href":1095,"dataGaName":1096,"dataGaLocation":764},"/sales/","talk to sales",{"text":1098,"config":1099},"Support portal",{"href":1100,"dataGaName":1101,"dataGaLocation":764},"https://support.gitlab.com/hc/en-us","support portal",{"text":1103,"config":1104},"Customer portal",{"href":1105,"dataGaName":1106,"dataGaLocation":764},"https://customers.gitlab.com/customers/sign_in/","customer portal",{"close":1108,"login":1109,"suggestions":1116},"Close",{"text":1110,"link":1111},"To search repositories and projects, login to",{"text":1112,"config":1113},"gitlab.com",{"href":778,"dataGaName":1114,"dataGaLocation":1115},"search login","search",{"text":1117,"default":1118},"Suggestions",[1119,1121,1125,1127,1131,1135],{"text":795,"config":1120},{"href":800,"dataGaName":795,"dataGaLocation":1115},{"text":1122,"config":1123},"Code Suggestions (AI)",{"href":1124,"dataGaName":1122,"dataGaLocation":1115},"/solutions/code-suggestions/",{"text":831,"config":1126},{"href":833,"dataGaName":831,"dataGaLocation":1115},{"text":1128,"config":1129},"GitLab on AWS",{"href":1130,"dataGaName":1128,"dataGaLocation":1115},"/partners/technology-partners/aws/",{"text":1132,"config":1133},"GitLab on Google Cloud",{"href":1134,"dataGaName":1132,"dataGaLocation":1115},"/partners/technology-partners/google-cloud-platform/",{"text":1136,"config":1137},"Why GitLab?",{"href":808,"dataGaName":1136,"dataGaLocation":1115},{"freeTrial":1139,"mobileIcon":1144,"desktopIcon":1149,"secondaryButton":1152},{"text":1140,"config":1141},"Start free trial",{"href":1142,"dataGaName":769,"dataGaLocation":1143},"https://gitlab.com/-/trials/new/","nav",{"altText":1145,"config":1146},"Gitlab Icon",{"src":1147,"dataGaName":1148,"dataGaLocation":1143},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203874/jypbw1jx72aexsoohd7x.svg","gitlab icon",{"altText":1145,"config":1150},{"src":1151,"dataGaName":1148,"dataGaLocation":1143},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203875/gs4c8p8opsgvflgkswz9.svg",{"text":1153,"config":1154},"Get Started",{"href":1155,"dataGaName":1156,"dataGaLocation":1143},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com/get-started/","get started",{"freeTrial":1158,"mobileIcon":1162,"desktopIcon":1164},{"text":1159,"config":1160},"Learn more about GitLab Duo",{"href":800,"dataGaName":1161,"dataGaLocation":1143},"gitlab duo",{"altText":1145,"config":1163},{"src":1147,"dataGaName":1148,"dataGaLocation":1143},{"altText":1145,"config":1165},{"src":1151,"dataGaName":1148,"dataGaLocation":1143},{"button":1167,"mobileIcon":1172,"desktopIcon":1174},{"text":1168,"config":1169},"/switch",{"href":1170,"dataGaName":1171,"dataGaLocation":1143},"#contact","switch",{"altText":1145,"config":1173},{"src":1147,"dataGaName":1148,"dataGaLocation":1143},{"altText":1145,"config":1175},{"src":1176,"dataGaName":1148,"dataGaLocation":1143},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1773335277/ohhpiuoxoldryzrnhfrh.png",{"freeTrial":1178,"mobileIcon":1183,"desktopIcon":1185},{"text":1179,"config":1180},"Back to pricing",{"href":913,"dataGaName":1181,"dataGaLocation":1143,"icon":1182},"back to pricing","GoBack",{"altText":1145,"config":1184},{"src":1147,"dataGaName":1148,"dataGaLocation":1143},{"altText":1145,"config":1186},{"src":1151,"dataGaName":1148,"dataGaLocation":1143},{"title":1188,"titleMobile":1189,"button":1190,"config":1195},"Duo Agent Platform delivers 400% ROI, per new Forrester Consulting study.","400% ROI: Forrester TEI for GitLab Duo",{"text":806,"config":1191},{"href":1192,"dataGaName":1193,"dataGaLocation":1194},"https://about.gitlab.com/blog/gitlab-duo-agent-platform-delivers-400-percent-roi/","forrester-tei-dap-banner","global-banner",{"layout":1196,"disabled":742},"release",{"data":1198},{"text":1199,"source":1200,"edit":1206,"contribute":1211,"config":1216,"items":1221,"minimal":1430},"Git is a trademark of Software Freedom Conservancy and our use of 'GitLab' is under license",{"text":1201,"config":1202},"View page source",{"href":1203,"dataGaName":1204,"dataGaLocation":1205},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/","page source","footer",{"text":1207,"config":1208},"Edit this page",{"href":1209,"dataGaName":1210,"dataGaLocation":1205},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/content/","web ide",{"text":1212,"config":1213},"Please contribute",{"href":1214,"dataGaName":1215,"dataGaLocation":1205},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/CONTRIBUTING.md/","please contribute",{"twitter":1217,"facebook":1218,"youtube":1219,"linkedin":1220},"https://twitter.com/gitlab","https://www.facebook.com/gitlab","https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg","https://www.linkedin.com/company/gitlab-com",[1222,1269,1322,1366,1398],{"title":911,"links":1223,"subMenu":1238},[1224,1228,1233],{"text":1225,"config":1226},"View plans",{"href":913,"dataGaName":1227,"dataGaLocation":1205},"view plans",{"text":1229,"config":1230},"Why Premium?",{"href":1231,"dataGaName":1232,"dataGaLocation":1205},"/pricing/premium/","why premium",{"text":1234,"config":1235},"Why Ultimate?",{"href":1236,"dataGaName":1237,"dataGaLocation":1205},"/pricing/ultimate/","why ultimate",[1239],{"title":1240,"links":1241},"Contact Us",[1242,1245,1247,1249,1254,1259,1264],{"text":1243,"config":1244},"Contact sales",{"href":1095,"dataGaName":774,"dataGaLocation":1205},{"text":1098,"config":1246},{"href":1100,"dataGaName":1101,"dataGaLocation":1205},{"text":1103,"config":1248},{"href":1105,"dataGaName":1106,"dataGaLocation":1205},{"text":1250,"config":1251},"Status",{"href":1252,"dataGaName":1253,"dataGaLocation":1205},"https://status.gitlab.com/","status",{"text":1255,"config":1256},"Terms of use",{"href":1257,"dataGaName":1258,"dataGaLocation":1205},"/terms/","terms of use",{"text":1260,"config":1261},"Privacy statement",{"href":1262,"dataGaName":1263,"dataGaLocation":1205},"/privacy/","privacy statement",{"text":1265,"config":1266},"Cookie preferences",{"dataGaName":1267,"dataGaLocation":1205,"id":1268,"isOneTrustButton":365},"cookie preferences","ot-sdk-btn",{"title":811,"links":1270,"subMenu":1279},[1271,1275],{"text":1272,"config":1273},"DevSecOps platform",{"href":793,"dataGaName":1274,"dataGaLocation":1205},"devsecops platform",{"text":1276,"config":1277},"AI-Assisted Development",{"href":800,"dataGaName":1278,"dataGaLocation":1205},"ai-assisted development",[1280],{"title":1281,"links":1282},"Topics",[1283,1287,1292,1297,1302,1307,1312,1317],{"text":1284,"config":1285},"CICD",{"href":47,"dataGaName":1286,"dataGaLocation":1205},"cicd",{"text":1288,"config":1289},"GitOps",{"href":1290,"dataGaName":1291,"dataGaLocation":1205},"/topics/gitops/","gitops",{"text":1293,"config":1294},"DevOps",{"href":1295,"dataGaName":1296,"dataGaLocation":1205},"/topics/devops/","devops",{"text":1298,"config":1299},"Version Control",{"href":1300,"dataGaName":1301,"dataGaLocation":1205},"/topics/version-control/","version control",{"text":1303,"config":1304},"DevSecOps",{"href":1305,"dataGaName":1306,"dataGaLocation":1205},"/topics/devsecops/","devsecops",{"text":1308,"config":1309},"Cloud Native",{"href":1310,"dataGaName":1311,"dataGaLocation":1205},"/topics/cloud-native/","cloud native",{"text":1313,"config":1314},"AI for Coding",{"href":1315,"dataGaName":1316,"dataGaLocation":1205},"/topics/devops/ai-for-coding/","ai for coding",{"text":1318,"config":1319},"Agentic AI",{"href":1320,"dataGaName":1321,"dataGaLocation":1205},"/topics/agentic-ai/","agentic ai",{"title":1323,"links":1324},"Solutions",[1325,1327,1329,1334,1338,1341,1345,1348,1350,1353,1356,1361],{"text":855,"config":1326},{"href":850,"dataGaName":855,"dataGaLocation":1205},{"text":844,"config":1328},{"href":827,"dataGaName":828,"dataGaLocation":1205},{"text":1330,"config":1331},"Agile development",{"href":1332,"dataGaName":1333,"dataGaLocation":1205},"/solutions/agile-delivery/","agile delivery",{"text":1335,"config":1336},"SCM",{"href":840,"dataGaName":1337,"dataGaLocation":1205},"source code management",{"text":1284,"config":1339},{"href":833,"dataGaName":1340,"dataGaLocation":1205},"continuous integration & delivery",{"text":1342,"config":1343},"Value stream management",{"href":883,"dataGaName":1344,"dataGaLocation":1205},"value stream management",{"text":1288,"config":1346},{"href":1347,"dataGaName":1291,"dataGaLocation":1205},"/solutions/gitops/",{"text":893,"config":1349},{"href":896,"dataGaName":897,"dataGaLocation":1205},{"text":1351,"config":1352},"Small business",{"href":902,"dataGaName":903,"dataGaLocation":1205},{"text":1354,"config":1355},"Public sector",{"href":908,"dataGaName":909,"dataGaLocation":1205},{"text":1357,"config":1358},"Education",{"href":1359,"dataGaName":1360,"dataGaLocation":1205},"/solutions/education/","education",{"text":1362,"config":1363},"Financial services",{"href":1364,"dataGaName":1365,"dataGaLocation":1205},"/solutions/finance/","financial services",{"title":916,"links":1367},[1368,1370,1372,1374,1377,1379,1382,1384,1386,1388,1390,1392,1394,1396],{"text":929,"config":1369},{"href":931,"dataGaName":932,"dataGaLocation":1205},{"text":934,"config":1371},{"href":936,"dataGaName":937,"dataGaLocation":1205},{"text":939,"config":1373},{"href":941,"dataGaName":942,"dataGaLocation":1205},{"text":944,"config":1375},{"href":946,"dataGaName":1376,"dataGaLocation":1205},"docs",{"text":967,"config":1378},{"href":969,"dataGaName":970,"dataGaLocation":1205},{"text":1380,"config":1381},"What's new",{"href":1027,"dataGaName":1028,"dataGaLocation":1205},{"text":962,"config":1383},{"href":964,"dataGaName":965,"dataGaLocation":1205},{"text":981,"config":1385},{"href":983,"dataGaName":984,"dataGaLocation":1205},{"text":989,"config":1387},{"href":991,"dataGaName":992,"dataGaLocation":1205},{"text":994,"config":1389},{"href":996,"dataGaName":997,"dataGaLocation":1205},{"text":999,"config":1391},{"href":1001,"dataGaName":1002,"dataGaLocation":1205},{"text":1004,"config":1393},{"href":1006,"dataGaName":1007,"dataGaLocation":1205},{"text":1009,"config":1395},{"href":1011,"dataGaName":1012,"dataGaLocation":1205},{"text":1014,"config":1397},{"href":1016,"dataGaName":1017,"dataGaLocation":1205},{"title":1030,"links":1399},[1400,1402,1404,1406,1408,1410,1414,1419,1421,1423,1425],{"text":1038,"config":1401},{"href":1040,"dataGaName":1032,"dataGaLocation":1205},{"text":1043,"config":1403},{"href":1045,"dataGaName":1046,"dataGaLocation":1205},{"text":1051,"config":1405},{"href":1053,"dataGaName":1054,"dataGaLocation":1205},{"text":1056,"config":1407},{"href":1058,"dataGaName":1059,"dataGaLocation":1205},{"text":1061,"config":1409},{"href":1063,"dataGaName":1064,"dataGaLocation":1205},{"text":1411,"config":1412},"Sustainability",{"href":1413,"dataGaName":1411,"dataGaLocation":1205},"/sustainability/",{"text":1415,"config":1416},"Diversity, inclusion and belonging (DIB)",{"href":1417,"dataGaName":1418,"dataGaLocation":1205},"/diversity-inclusion-belonging/","Diversity, inclusion and belonging",{"text":1066,"config":1420},{"href":1068,"dataGaName":1069,"dataGaLocation":1205},{"text":1076,"config":1422},{"href":1078,"dataGaName":1079,"dataGaLocation":1205},{"text":1081,"config":1424},{"href":1083,"dataGaName":1084,"dataGaLocation":1205},{"text":1426,"config":1427},"Modern Slavery Transparency Statement",{"href":1428,"dataGaName":1429,"dataGaLocation":1205},"https://handbook.gitlab.com/handbook/legal/modern-slavery-act-transparency-statement/","modern slavery transparency statement",{"items":1431},[1432,1435,1438],{"text":1433,"config":1434},"Terms",{"href":1257,"dataGaName":1258,"dataGaLocation":1205},{"text":1436,"config":1437},"Cookies",{"dataGaName":1267,"dataGaLocation":1205,"id":1268,"isOneTrustButton":365},{"text":1439,"config":1440},"Privacy",{"href":1262,"dataGaName":1263,"dataGaLocation":1205},[1442],{"id":1443,"title":7,"body":741,"config":1444,"content":1446,"description":741,"extension":1450,"meta":1451,"navigation":365,"path":1452,"seo":1453,"stem":1454,"__hash__":1455},"blogAuthors/en-us/blog/authors/fabio-pitino.yml",{"template":1445},"BlogAuthor",{"name":7,"config":1447},{"headshot":1448,"ctfId":1449},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749659958/Blog/Author%20Headshots/fabiopitino-headshot.jpg","fabiopitino","yml",{},"/en-us/blog/authors/fabio-pitino",{},"en-us/blog/authors/fabio-pitino","Z13_RNj1RdIE3Ac9JR_WAE9yNsZLQCBC8l-w4fInLFY",[1457,1466,1474],{"title":1458,"description":1459,"heroImage":1460,"category":737,"date":1461,"authors":1462,"slug":1465,"externalUrl":741},"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",[1463,1464],"Mathias Ewald","Martin Paloncy, Edgeless Systems","confidential-ai-for-gitlab-self-hosted",{"title":1467,"description":1468,"heroImage":1469,"category":737,"date":1470,"authors":1471,"slug":1473,"externalUrl":741},"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",[1472],"Lysanne Pinto","green-devops-carbon-measurement-cicd-pipeline",{"title":1475,"description":1476,"heroImage":1477,"category":737,"date":1478,"authors":1479,"slug":1481,"externalUrl":741},"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",[1480],"Paul Meresanu","how-to-build-ci-cd-observability-at-scale",{"promotions":1483},[1484,1498,1510,1522],{"id":1485,"categories":1486,"header":1488,"text":1489,"button":1490,"image":1495},"ai-modernization",[1487],"ai","Is AI achieving its promise at scale?","Quiz will take 5 minutes or less",{"text":1491,"config":1492},"Get your AI maturity score",{"href":1493,"dataGaName":1494,"dataGaLocation":970},"/assessments/ai-modernization-assessment/","modernization assessment",{"config":1496},{"src":1497},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/qix0m7kwnd8x2fh1zq49.png",{"id":1499,"categories":1500,"header":1502,"text":1489,"button":1503,"image":1507},"devops-modernization",[1501,1306],"product","Are you just managing tools or shipping innovation?",{"text":1504,"config":1505},"Get your DevOps maturity score",{"href":1506,"dataGaName":1494,"dataGaLocation":970},"/assessments/devops-modernization-assessment/",{"config":1508},{"src":1509},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138785/eg818fmakweyuznttgid.png",{"id":1511,"categories":1512,"header":1514,"text":1489,"button":1515,"image":1519},"security-modernization",[1513],"security","Are you trading speed for security?",{"text":1516,"config":1517},"Get your security maturity score",{"href":1518,"dataGaName":1494,"dataGaLocation":970},"/assessments/security-modernization-assessment/",{"config":1520},{"src":1521},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/p4pbqd9nnjejg5ds6mdk.png",{"id":1523,"paths":1524,"header":1527,"text":1528,"button":1529,"image":1534},"github-azure-migration",[1525,1526],"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":1530,"config":1531},"See how GitLab compares to GitHub",{"href":1532,"dataGaName":1533,"dataGaLocation":970},"/compare/gitlab-vs-github/github-azure-migration/","github azure migration",{"config":1535},{"src":1509},{"header":1537,"blurb":1538,"button":1539,"secondaryButton":1544},"Start building faster today","See what your team can do with the intelligent orchestration platform for DevSecOps.\n",{"text":1540,"config":1541},"Get your free trial",{"href":1542,"dataGaName":769,"dataGaLocation":1543},"https://gitlab.com/-/trial_registrations/new?glm_content=default-saas-trial&glm_source=about.gitlab.com/","feature",{"text":1243,"config":1545},{"href":1095,"dataGaName":774,"dataGaLocation":1543},1786734866036]