[{"data":1,"prerenderedAt":1589},["ShallowReactive",2],{"/blog/deploy-remix-with-gitlab-and-cloudflare":3,"navigation-en-us":804,"banner-en-us":1230,"footer-en-us":1240,"blog-post-authors-en-us-Janis Altherr":1485,"blog-related-posts-en-us-deploy-remix-with-gitlab-and-cloudflare":1500,"blog-promotions-en-us":1526,"next-steps-en-us":1579},{"id":4,"title":5,"authors":6,"body":8,"category":783,"date":784,"description":785,"extension":786,"externalUrl":787,"faq":787,"featured":788,"heroImage":789,"meta":790,"navigation":450,"path":791,"seo":792,"slug":796,"stem":797,"tags":798,"template":802,"updatedDate":787,"__hash__":803},"blogPosts/en-us/blog/deploy-remix-with-gitlab-and-cloudflare.md","How to publish a Remix app to the edge with GitLab and Cloudflare",[7],"Janis Altherr",{"type":9,"value":10,"toc":771},"minimark",[11,21,24,27,30,35,38,75,78,86,89,130,134,137,148,156,159,201,205,220,225,228,235,242,245,249,269,283,289,301,317,323,338,345,351,357,377,392,405,411,415,422,560,568,571,603,616,625,632,638,641,645,648,659,665,668,674,680,690,696,714,727,730,736,739,743,767],[12,13,14,20],"p",{},[15,16,19],"a",{"href":17,"rel":18},"https://remix.run",[],"Remix"," has had a significant impact in the frontend space.\nAfter eons of backend frameworks providing some sort of frontend options that are more or\nless hated by frontend engineers, followed by frontend frameworks that\nrequired a separate API for the most simple tasks that were a pain to\nmaintain, now suddenly there are frontend frameworks that you can write\nbackend code with.",[12,22,23],{},"This is ideal as an application scales: Remix offers the comfort of writing\nserver-side code, but should the business logic start to exceed the\ncapabilities of Remix, it's easy to move code to an API on a per-request basis.\nThis comes without the need to rewrite the entire application logic, while\nstill retaining server-side-rendering or even pre-rendering capabilities!",[12,25,26],{},"The most performant way to deploy a Remix app is to the edge. This means\nthat small instances of your Remix app are run on a server close to the requesting\nuser. An edge network consists of hundreds of\nservers all over the world, so you can be sure the network latency for the\nuser stays low.",[12,28,29],{},"Currently the most popular edge service capable of running Remix apps are\nCloudflare Workers. Not only does Cloudflare offer a generous free tier,\nWorkers are also extremely easy to deploy using GitLab CI/CD.\nHere's how to create a Remix app and then deploy it to Cloudflare Workers.",[31,32,34],"h2",{"id":33},"create-your-remix-app","Create your Remix app",[12,36,37],{},"Create your Remix app locally using:",[39,40,45],"pre",{"className":41,"code":42,"language":43,"meta":44,"style":44},"language-bash shiki shiki-themes github-light","npx create-remix@latest \u003Cmy-app-name>\n","bash","",[46,47,48],"code",{"__ignoreMap":44},[49,50,53,57,61,65,68,72],"span",{"class":51,"line":52},"line",1,[49,54,56],{"class":55},"s7eDp","npx",[49,58,60],{"class":59},"sYBdl"," create-remix@latest",[49,62,64],{"class":63},"sD7c4"," \u003C",[49,66,67],{"class":59},"my-app-nam",[49,69,71],{"class":70},"sgsFI","e",[49,73,74],{"class":63},">\n",[12,76,77],{},"The CLI will now guide you through a series of questions. Some of those you\nmay answer as you prefer, but answer the following questions as indicated\nbelow:",[39,79,84],{"className":80,"code":82,"language":83,"meta":44},[81],"language-text","? What type of app do you want to create? \n> choose \"Just the Basics\"\n\n? Where do you want to deploy? [...]\n> choose \"Cloudflare Workers\"\n\n? Do you want me to run `npm install`?\n> answer \"Yes\"\n","text",[46,85,82],{"__ignoreMap":44},[12,87,88],{},"Initialize the repository and add the first commit:",[39,90,94],{"className":91,"code":92,"language":93,"meta":44,"style":44},"language-shell shiki shiki-themes github-light","git init\ngit add .\ngit commit -m \"initial commit\"\n","shell",[46,95,96,104,115],{"__ignoreMap":44},[49,97,98,101],{"class":51,"line":52},[49,99,100],{"class":55},"git",[49,102,103],{"class":59}," init\n",[49,105,107,109,112],{"class":51,"line":106},2,[49,108,100],{"class":55},[49,110,111],{"class":59}," add",[49,113,114],{"class":59}," .\n",[49,116,118,120,123,127],{"class":51,"line":117},3,[49,119,100],{"class":55},[49,121,122],{"class":59}," commit",[49,124,126],{"class":125},"sYu0t"," -m",[49,128,129],{"class":59}," \"initial commit\"\n",[31,131,133],{"id":132},"create-the-project-in-gitlab","Create the project in GitLab",[12,135,136],{},"You can't push the code as we have yet to set up the remote repository.\nVisit GitLab and create a new project. When asked, select \"Create blank\nproject.\"",[12,138,139,140,143,144,147],{},"In the project setup dialog, select ",[46,141,142],{},"Edge Computing"," as the ",[46,145,146],{},"Deployment  target",". Choose the visibility level however you like as this affects your\nsource code visibility.",[12,149,150,151,155],{},"Make sure you unset the checkbox next to ",[152,153,154],"strong",{},"Initialize repository with a\nREADME",", otherwise GitLab will begin a new Git history that you will have to reconcile\nwith your existing local one.",[12,157,158],{},"Once the project is set up, follow the instructions on how to add an\nexisting repository – if you've followed the above instructions to the letter\nyou don't have an existing remote yet, so you can run this simplified set of\ncommands:",[39,160,162],{"className":91,"code":161,"language":93,"meta":44,"style":44},"git remote add origin \u003Cgit-project-url>\ngit push -u origin main\n",[46,163,164,186],{"__ignoreMap":44},[49,165,166,168,171,173,176,178,181,184],{"class":51,"line":52},[49,167,100],{"class":55},[49,169,170],{"class":59}," remote",[49,172,111],{"class":59},[49,174,175],{"class":59}," origin",[49,177,64],{"class":63},[49,179,180],{"class":59},"git-project-ur",[49,182,183],{"class":70},"l",[49,185,74],{"class":63},[49,187,188,190,193,196,198],{"class":51,"line":106},[49,189,100],{"class":55},[49,191,192],{"class":59}," push",[49,194,195],{"class":125}," -u",[49,197,175],{"class":59},[49,199,200],{"class":59}," main\n",[31,202,204],{"id":203},"configure-cloudflare","Configure Cloudflare",[12,206,207,208,213,214,219],{},"Now set up your Cloudflare account to enable deployments from GitLab.\n",[15,209,212],{"href":210,"rel":211},"https://dash.cloudflare.com/login",[],"Login"," or ",[15,215,218],{"href":216,"rel":217},"https://dash.cloudflare.com/sign-up",[],"create an account",".",[221,222,224],"h3",{"id":223},"subscribe-to-a-workers-plan","Subscribe to a Workers plan",[12,226,227],{},"If you are creating a Worker for the first time, you will have to sign up for a Workers plan in Cloudflare.",[12,229,230,231,234],{},"In the Cloudflare dashboard's left sidebar click the entry ",[152,232,233],{},"Workers",". Let\nCloudflare guide you through the setup.",[12,236,237],{},[238,239],"img",{"alt":240,"src":241},"Screenshot: Signing up for Workers in Cloudflare","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398951/blog/Content%20Images/remix-cloudflare/workers_onboarding.png",[12,243,244],{},"Once you're back to the Workers overview page, continue below.",[221,246,248],{"id":247},"obtain-an-api-token","Obtain an API token",[12,250,251,252,257,258,261,262,261,265,268],{},"To be able to deploy your Cloudflare Worker from a GitLab pipeline you will need\nan API token. To do so, log in to the Cloudflare dashboard, then open the ",[15,253,256],{"href":254,"rel":255},"https://dash.cloudflare.com/profile/api-tokens",[],"API\ntokens page"," (or find it\nmanually via the ",[152,259,260],{},"user icon"," > ",[152,263,264],{},"My Profile",[152,266,267],{},"Api Tokens",").",[12,270,271,272,275,276,279,280,219],{},"Click ",[152,273,274],{},"Create Token",". Find ",[152,277,278],{},"Edit Cloudflare Workers",", click ",[152,281,282],{},"use\ntemplate",[12,284,285],{},[238,286],{"alt":287,"src":288},"Screenshot: Select API Token template \"Edit Cloudflare Workers\"","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398950/blog/Content%20Images/remix-cloudflare/api_token_template_selection.png",[12,290,291,292,295,296,300],{},"Under ",[152,293,294],{},"Account Resources"," choose ",[297,298,299],"em",{},"Include"," and your account name.",[12,302,291,303,295,306,308,309,312,313,316],{},[152,304,305],{},"Zone Resources",[297,307,299],{},", ",[297,310,311],{},"Specific Zone"," and your site's\ndomain. If you haven't set up a domain, you can use a less specific rule\nsuch as ",[297,314,315],{},"All zones from an account",", although we don't recommend doing this; the API token could potentially be used beyond its scope if you add more zones to your Cloudflare account later.",[12,318,319],{},[238,320],{"alt":321,"src":322},"Screenshot: API Token Account and Zone Settings","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398949/blog/Content%20Images/remix-cloudflare/api_token_rules.png",[12,324,325,328,329,332,333,219],{},[152,326,327],{},"Note:"," If you have more than one account associated with the API token used\nduring deployment, you will have to update your project's ",[46,330,331],{},"wrangler.toml"," file\nto use the correct account. ",[15,334,337],{"href":335,"rel":336},"https://developers.cloudflare.com/workers/wrangler/ci-cd/#account-id",[],"Read more in the Cloudflare documentation",[12,339,340,341,344],{},"Once you're done setting up the API token, click ",[152,342,343],{},"Continue to summary",",\nand verify your selections. It should look like this:",[12,346,347],{},[238,348],{"alt":349,"src":350},"Screenshot: API Token Summary View","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398949/blog/Content%20Images/remix-cloudflare/api_token_summary.png",[12,352,353,354,356],{},"If you're happy, click ",[152,355,274],{},". Cloudflare will then show you the new\ntoken.",[12,358,359,360,261,363,275,366,369,370,373,374,219],{},"Copy the token and save it in GitLab: Open your project in GitLab, then\nvisit ",[152,361,362],{},"Settings",[152,364,365],{},"CI/CD",[152,367,368],{},"Variables"," and click ",[152,371,372],{},"Expand",". Click\n",[152,375,376],{},"Add Variable",[12,378,379,380,383,384,387,388,391],{},"In the ",[152,381,382],{},"Key"," field, enter ",[46,385,386],{},"CLOUDFLARE_API_TOKEN",".\nIn the ",[152,389,390],{},"Value"," field, paste the API token from Cloudflare.",[12,393,394,395,398,399,402,403,219],{},"Now make sure your token isn't leaked in any logs: Check both ",[152,396,397],{},"Protect","\nand ",[152,400,401],{},"Mask",". When done, click ",[152,404,376],{},[12,406,407],{},[238,408],{"alt":409,"src":410},"Adding a Variable in GitLab","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398950/blog/Content%20Images/remix-cloudflare/adding_cf_api_token_as_variable.gif",[31,412,414],{"id":413},"create-the-deployment-pipeline","Create the deployment pipeline",[12,416,417,418,421],{},"The last step is to create a GitLab pipeline. In your local repository root\nfolder, create a file named ",[46,419,420],{},".gitlab-ci.yml"," and add the following content:",[39,423,427],{"className":424,"code":425,"language":426,"meta":44,"style":44},"language-yaml shiki shiki-themes github-light","stages:\n- deploy\n\ndeploy-worker:\n    image: node:lts\n    stage: deploy\n    environment: production\n    before_script:\n      # install dependencies\n      - npm ci\n    script:\n      - npm run deploy\n    rules:\n      # This rule triggers this job after any push to the default branch\n      - if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH\n\n","yaml",[46,428,429,438,446,452,460,472,482,493,501,508,517,525,533,541,547],{"__ignoreMap":44},[49,430,431,435],{"class":51,"line":52},[49,432,434],{"class":433},"shJU0","stages",[49,436,437],{"class":70},":\n",[49,439,440,443],{"class":51,"line":106},[49,441,442],{"class":70},"- ",[49,444,445],{"class":59},"deploy\n",[49,447,448],{"class":51,"line":117},[49,449,451],{"emptyLinePlaceholder":450},true,"\n",[49,453,455,458],{"class":51,"line":454},4,[49,456,457],{"class":433},"deploy-worker",[49,459,437],{"class":70},[49,461,463,466,469],{"class":51,"line":462},5,[49,464,465],{"class":433},"    image",[49,467,468],{"class":70},": ",[49,470,471],{"class":59},"node:lts\n",[49,473,475,478,480],{"class":51,"line":474},6,[49,476,477],{"class":433},"    stage",[49,479,468],{"class":70},[49,481,445],{"class":59},[49,483,485,488,490],{"class":51,"line":484},7,[49,486,487],{"class":433},"    environment",[49,489,468],{"class":70},[49,491,492],{"class":59},"production\n",[49,494,496,499],{"class":51,"line":495},8,[49,497,498],{"class":433},"    before_script",[49,500,437],{"class":70},[49,502,504],{"class":51,"line":503},9,[49,505,507],{"class":506},"sAwPA","      # install dependencies\n",[49,509,511,514],{"class":51,"line":510},10,[49,512,513],{"class":70},"      - ",[49,515,516],{"class":59},"npm ci\n",[49,518,520,523],{"class":51,"line":519},11,[49,521,522],{"class":433},"    script",[49,524,437],{"class":70},[49,526,528,530],{"class":51,"line":527},12,[49,529,513],{"class":70},[49,531,532],{"class":59},"npm run deploy\n",[49,534,536,539],{"class":51,"line":535},13,[49,537,538],{"class":433},"    rules",[49,540,437],{"class":70},[49,542,544],{"class":51,"line":543},14,[49,545,546],{"class":506},"      # This rule triggers this job after any push to the default branch\n",[49,548,550,552,555,557],{"class":51,"line":549},15,[49,551,513],{"class":70},[49,553,554],{"class":433},"if",[49,556,468],{"class":70},[49,558,559],{"class":59},"$CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH\n",[12,561,562,563,219],{},"To learn more about how to configure your GitLab pipeline, read our\n",[15,564,567],{"href":565,"rel":566},"https://docs.gitlab.com/ci/",[],"documentation",[12,569,570],{},"Now add the file to the repository:",[39,572,574],{"className":91,"code":573,"language":93,"meta":44,"style":44},"git add .gitlab-ci.yml\ngit commit -m \"Add Deployment Pipeline\"\ngit push\n",[46,575,576,585,596],{"__ignoreMap":44},[49,577,578,580,582],{"class":51,"line":52},[49,579,100],{"class":55},[49,581,111],{"class":59},[49,583,584],{"class":59}," .gitlab-ci.yml\n",[49,586,587,589,591,593],{"class":51,"line":106},[49,588,100],{"class":55},[49,590,122],{"class":59},[49,592,126],{"class":125},[49,594,595],{"class":59}," \"Add Deployment Pipeline\"\n",[49,597,598,600],{"class":51,"line":117},[49,599,100],{"class":55},[49,601,602],{"class":59}," push\n",[12,604,605,606,261,608,611,612,615],{},"This last push will immediately run this pipeline. To monitor the pipeline\nprogress, open GitLab. In the left sidebar, find ",[152,607,365],{},[152,609,610],{},"Pipelines",".\nOnce the pipeline is marked as ",[297,613,614],{},"passed",", your Remix site is live!",[12,617,618,619,622,623,219],{},"If you've used the create-app instructions from this blogpost, your app should\nhave been configured to use the app name as the Worker's name. Check the\n",[46,620,621],{},"name"," setting in your project's ",[46,624,331],{},[12,626,627,628,631],{},"Go to ",[46,629,630],{},"https://\u003Cworker-name>.\u003Ccloudflare-account-name>.workers.dev"," to see\nyour Remix site in action. Congratulations!",[12,633,634,635,637],{},"In your Cloudflare dashboard, you can monitor your new app by selecting\n",[152,636,233],{}," from the left sidebar and then clicking on the Worker with the\nname of your app.",[12,639,640],{},"From now on, any push to your repositories default branch will automatically\nbe built and deployed to Cloudflare.",[221,642,644],{"id":643},"use-a-custom-domain-for-your-app","Use a custom Domain for your app",[12,646,647],{},"If you want to use your own domain, set up your website as a resource now.",[12,649,650,651,654,655,658],{},"In the left sidebar, click on ",[152,652,653],{},"Websites",". In the main window, find and click\nthe ",[152,656,657],{},"Add Site"," button.",[12,660,661],{},[238,662],{"alt":663,"src":664},"Screenshot: Add a new site in Cloudflare","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398915/blog/Content%20Images/remix-cloudflare/add_site.png",[12,666,667],{},"Now enter your site's domain. Select a plan that suits your needs.\nFollow the DNS setup instructions provided on the following pages.",[12,669,670,671,673],{},"Once you have set up your domain as a website in Cloudflare, go to the\nwebsite settings. (In the left sidebar click ",[152,672,653],{},", then select your\nsite).",[12,675,676],{},[238,677],{"alt":678,"src":679},"Screenshot: Find your website on the Cloudflare Dashboard","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398914/blog/Content%20Images/remix-cloudflare/add_route_step_1.png",[12,681,682,683,686,687,219],{},"The left sidebar now shows the detail navigation for the selected website.\nClick ",[152,684,685],{},"Workers Routes",", then click ",[152,688,689],{},"Add Route",[12,691,692],{},[238,693],{"alt":694,"src":695},"Screenshot: Add a new route to your Site","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398914/blog/Content%20Images/remix-cloudflare/add_route_step_2.png",[12,697,698,699,702,703,706,707,710,711,268],{},"In the Add Route Modal you can add a dynamic pattern to let Cloudflare know which requests to route to your Worker.\nFor Remix apps that's usually all of them, so if your site's domain is\n",[46,700,701],{},"my-site.com",", use ",[46,704,705],{},"my-site.com/*",". You can also redirect all subdomain\nrequests to the worker by using ",[46,708,709],{},"*.my-site.com/*"," (this is useful if you\nwould like to also serve your site at ",[46,712,713],{},"www.my-site.com",[12,715,291,716,719,720,723,724,219],{},[152,717,718],{},"Service",", select your newly created Worker.\nUnder ",[152,721,722],{},"Environment",", select ",[152,725,726],{},"production",[12,728,729],{},"Click \"Save\".",[12,731,732],{},[238,733],{"alt":734,"src":735},"Screenshot: Add route modal","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398914/blog/Content%20Images/remix-cloudflare/add_route_step_3.png",[12,737,738],{},"Once the DNS servers are updated, your Remix site should be accessible with\nyour custom domain.",[31,740,742],{"id":741},"read-more","Read More",[744,745,746,754,761],"ul",{},[747,748,749],"li",{},[15,750,753],{"href":751,"rel":752},"https://developers.cloudflare.com/workers/wrangler/configuration/",[],"Learn more about Cloudflare Workers",[747,755,756],{},[15,757,760],{"href":758,"rel":759},"https://remix.run/docs/en/v1",[],"Check out the Remix docs",[747,762,763],{},[15,764,766],{"href":565,"rel":765},[],"Learn about GitLab pipelines",[768,769,770],"style",{},"html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}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 .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .shJU0, html code.shiki .shJU0{--shiki-default:#22863A}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}",{"title":44,"searchDepth":106,"depth":106,"links":772},[773,774,775,779,782],{"id":33,"depth":106,"text":34},{"id":132,"depth":106,"text":133},{"id":203,"depth":106,"text":204,"children":776},[777,778],{"id":223,"depth":117,"text":224},{"id":247,"depth":117,"text":248},{"id":413,"depth":106,"text":414,"children":780},[781],{"id":643,"depth":117,"text":644},{"id":741,"depth":106,"text":742},"engineering","2022-11-21","Learn how to deploy a Remix app with GitLab and Cloudflare Workers.","md",null,false,"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749682517/Blog/Hero%20Images/ryoji-hayasaka-0UZj73PQVew-unsplash.jpg",{},"/en-us/blog/deploy-remix-with-gitlab-and-cloudflare",{"title":5,"description":785,"ogTitle":5,"ogDescription":785,"noIndex":788,"ogImage":789,"ogUrl":793,"ogSiteName":794,"ogType":795,"canonicalUrls":793},"https://about.gitlab.com/blog/deploy-remix-with-gitlab-and-cloudflare","https://about.gitlab.com","article","deploy-remix-with-gitlab-and-cloudflare","en-us/blog/deploy-remix-with-gitlab-and-cloudflare",[799,800,801],"tutorial","integrations","product","BlogPost","NEgXn-TpZABt484szQ0WxOnnF4Xu5RKyqPXzok_hrqw",{"logo":805,"freeTrial":810,"sales":815,"login":820,"items":825,"search":1150,"minimal":1181,"duo":1200,"switchNav":1209,"pricingDeployment":1220},{"config":806},{"href":807,"dataGaName":808,"dataGaLocation":809},"/","gitlab logo","header",{"text":811,"config":812},"Get free trial",{"href":813,"dataGaName":814,"dataGaLocation":809},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com&glm_content=default-saas-trial/","free trial",{"text":816,"config":817},"Request a demo",{"href":818,"dataGaName":819,"dataGaLocation":809},"/sales/?contact-topic=request-demo","sales",{"text":821,"config":822},"Sign in",{"href":823,"dataGaName":824,"dataGaLocation":809},"https://gitlab.com/users/sign_in/","sign in",[826,855,954,959,1072,1128],{"text":827,"config":828,"menu":830},"Platform",{"dataNavLevelOne":829},"platform",{"type":831,"columns":832},"cards",[833,839,847],{"title":827,"description":834,"link":835},"The intelligent orchestration platform for DevSecOps",{"text":836,"config":837},"Explore our Platform",{"href":838,"dataGaName":829,"dataGaLocation":809},"/platform/",{"title":840,"description":841,"link":842},"GitLab Duo Agent Platform","Agentic AI for the entire software lifecycle",{"text":843,"config":844},"Meet GitLab Duo",{"href":845,"dataGaName":846,"dataGaLocation":809},"/gitlab-duo-agent-platform/","gitlab duo agent platform",{"title":848,"description":849,"link":850},"Why GitLab","See the top reasons enterprises choose GitLab",{"text":851,"config":852},"Learn more",{"href":853,"dataGaName":854,"dataGaLocation":809},"/why-gitlab/","why gitlab",{"text":856,"left":450,"config":857,"menu":859},"Product",{"dataNavLevelOne":858},"solutions",{"type":860,"link":861,"columns":865,"feature":933},"lists",{"text":862,"config":863},"View all Solutions",{"href":864,"dataGaName":858,"dataGaLocation":809},"/solutions/",[866,889,912],{"title":867,"description":868,"link":869,"items":874},"Automation","CI/CD and automation to accelerate deployment",{"config":870},{"icon":871,"href":872,"dataGaName":873,"dataGaLocation":809},"AutomatedCodeAlt","/solutions/delivery-automation/","automated software delivery",[875,878,881,885],{"text":365,"config":876},{"href":877,"dataGaLocation":809,"dataGaName":365},"/solutions/continuous-integration/",{"text":840,"config":879},{"href":845,"dataGaLocation":809,"dataGaName":880},"gitlab duo agent platform - product menu",{"text":882,"config":883},"Source Code Management",{"href":884,"dataGaLocation":809,"dataGaName":882},"/solutions/source-code-management/",{"text":886,"config":887},"Automated Software Delivery",{"href":872,"dataGaLocation":809,"dataGaName":888},"Automated software delivery",{"title":890,"description":891,"link":892,"items":897},"Security","Deliver code faster without compromising security",{"config":893},{"href":894,"dataGaName":895,"dataGaLocation":809,"icon":896},"/solutions/application-security-testing/","security and compliance","ShieldCheckLight",[898,902,907],{"text":899,"config":900},"Application Security Testing",{"href":894,"dataGaName":901,"dataGaLocation":809},"Application security testing",{"text":903,"config":904},"Software Supply Chain Security",{"href":905,"dataGaLocation":809,"dataGaName":906},"/solutions/supply-chain/","Software supply chain security",{"text":908,"config":909},"Software Compliance",{"href":910,"dataGaName":911,"dataGaLocation":809},"/solutions/software-compliance/","software compliance",{"title":913,"link":914,"items":919},"Measurement",{"config":915},{"icon":916,"href":917,"dataGaName":918,"dataGaLocation":809},"DigitalTransformation","/solutions/visibility-measurement/","visibility and measurement",[920,924,928],{"text":921,"config":922},"Visibility & Measurement",{"href":917,"dataGaLocation":809,"dataGaName":923},"Visibility and Measurement",{"text":925,"config":926},"Value Stream Management",{"href":927,"dataGaLocation":809,"dataGaName":925},"/solutions/value-stream-management/",{"text":929,"config":930},"Analytics & Insights",{"href":931,"dataGaLocation":809,"dataGaName":932},"/solutions/analytics-and-insights/","Analytics and insights",{"title":934,"type":860,"items":935},"GitLab for",[936,942,948],{"text":937,"config":938},"Enterprise",{"icon":939,"href":940,"dataGaLocation":809,"dataGaName":941},"Building","/enterprise/","enterprise",{"text":943,"config":944},"Small Business",{"icon":945,"href":946,"dataGaLocation":809,"dataGaName":947},"Work","/small-business/","small business",{"text":949,"config":950},"Public Sector",{"icon":951,"href":952,"dataGaLocation":809,"dataGaName":953},"Organization","/solutions/public-sector/","public sector",{"text":955,"config":956},"Pricing",{"href":957,"dataGaName":958,"dataGaLocation":809,"dataNavLevelOne":958},"/pricing/","pricing",{"text":960,"config":961,"menu":963},"Resources",{"dataNavLevelOne":962},"resources",{"type":860,"link":964,"columns":968,"feature":1061},{"text":965,"config":966},"View all resources",{"href":967,"dataGaName":962,"dataGaLocation":809},"/resources/",[969,1001,1028],{"title":970,"items":971},"Getting started",[972,977,982,987,992,997],{"text":973,"config":974},"Install",{"href":975,"dataGaName":976,"dataGaLocation":809},"/install/","install",{"text":978,"config":979},"Quick start guides",{"href":980,"dataGaName":981,"dataGaLocation":809},"/get-started/","quick setup checklists",{"text":983,"config":984},"Learn",{"href":985,"dataGaLocation":809,"dataGaName":986},"https://university.gitlab.com/","learn",{"text":988,"config":989},"Product documentation",{"href":990,"dataGaName":991,"dataGaLocation":809},"https://docs.gitlab.com/","product documentation",{"text":993,"config":994},"Best practice videos",{"href":995,"dataGaName":996,"dataGaLocation":809},"/getting-started-videos/","best practice videos",{"text":998,"config":999},"Integrations",{"href":1000,"dataGaName":800,"dataGaLocation":809},"/integrations/",{"title":1002,"items":1003},"Discover",[1004,1009,1014,1019,1023],{"text":1005,"config":1006},"Customer success stories",{"href":1007,"dataGaName":1008,"dataGaLocation":809},"/customers/","customer success stories",{"text":1010,"config":1011},"Blog",{"href":1012,"dataGaName":1013,"dataGaLocation":809},"/blog/","blog",{"text":1015,"config":1016},"Demo Hub",{"href":1017,"dataGaName":1018,"dataGaLocation":809},"/demo-hub/","demo hub",{"text":1020,"config":1021},"The Source",{"href":1022,"dataGaName":1013,"dataGaLocation":809},"/the-source/",{"text":1024,"config":1025},"Remote",{"href":1026,"dataGaName":1027,"dataGaLocation":809},"https://handbook.gitlab.com/handbook/company/culture/all-remote/","remote",{"title":1029,"items":1030},"Connect",[1031,1036,1041,1046,1051,1056],{"text":1032,"config":1033},"GitLab Services",{"href":1034,"dataGaName":1035,"dataGaLocation":809},"/services/","services",{"text":1037,"config":1038},"Contribute",{"href":1039,"dataGaName":1040,"dataGaLocation":809},"https://contributors.gitlab.com","contribute",{"text":1042,"config":1043},"Community",{"href":1044,"dataGaName":1045,"dataGaLocation":809},"/community/","community",{"text":1047,"config":1048},"Forum",{"href":1049,"dataGaName":1050,"dataGaLocation":809},"https://forum.gitlab.com/","forum",{"text":1052,"config":1053},"Events",{"href":1054,"dataGaName":1055,"dataGaLocation":809},"/events/","events",{"text":1057,"config":1058},"Partners",{"href":1059,"dataGaName":1060,"dataGaLocation":809},"/partners/","partners",{"config":1062,"title":1065,"text":1066,"link":1067},{"background":1063,"textColor":1064},"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":1068,"config":1069},"Read the latest",{"href":1070,"dataGaName":1071,"dataGaLocation":809},"/whats-new/","whats new",{"text":1073,"config":1074,"menu":1076},"Company",{"dataNavLevelOne":1075},"company",{"type":860,"columns":1077},[1078],{"items":1079},[1080,1085,1091,1093,1098,1103,1108,1113,1118,1123],{"text":1081,"config":1082},"About",{"href":1083,"dataGaName":1084,"dataGaLocation":809},"/company/","about",{"text":1086,"config":1087,"footerGa":1090},"Jobs",{"href":1088,"dataGaName":1089,"dataGaLocation":809},"/jobs/","jobs",{"dataGaName":1089},{"text":1052,"config":1092},{"href":1054,"dataGaName":1055,"dataGaLocation":809},{"text":1094,"config":1095},"Leadership",{"href":1096,"dataGaName":1097,"dataGaLocation":809},"/company/team/e-group/","leadership",{"text":1099,"config":1100},"Handbook",{"href":1101,"dataGaName":1102,"dataGaLocation":809},"https://handbook.gitlab.com/","handbook",{"text":1104,"config":1105},"Investor relations",{"href":1106,"dataGaName":1107,"dataGaLocation":809},"https://ir.gitlab.com/overview/default.aspx","investor relations",{"text":1109,"config":1110},"Trust Center",{"href":1111,"dataGaName":1112,"dataGaLocation":809},"/security/","trust center",{"text":1114,"config":1115},"AI Transparency Center",{"href":1116,"dataGaName":1117,"dataGaLocation":809},"/ai-transparency-center/","ai transparency center",{"text":1119,"config":1120},"Newsletter",{"href":1121,"dataGaName":1122,"dataGaLocation":809},"/company/contact/#contact-forms","newsletter",{"text":1124,"config":1125},"Press",{"href":1126,"dataGaName":1127,"dataGaLocation":809},"/press/","press",{"text":1129,"config":1130,"menu":1131},"Contact us",{"dataNavLevelOne":1075},{"type":860,"columns":1132},[1133],{"items":1134},[1135,1140,1145],{"text":1136,"config":1137},"Talk to sales",{"href":1138,"dataGaName":1139,"dataGaLocation":809},"/sales/","talk to sales",{"text":1141,"config":1142},"Support portal",{"href":1143,"dataGaName":1144,"dataGaLocation":809},"https://support.gitlab.com/hc/en-us","support portal",{"text":1146,"config":1147},"Customer portal",{"href":1148,"dataGaName":1149,"dataGaLocation":809},"https://customers.gitlab.com/customers/sign_in/","customer portal",{"close":1151,"login":1152,"suggestions":1159},"Close",{"text":1153,"link":1154},"To search repositories and projects, login to",{"text":1155,"config":1156},"gitlab.com",{"href":823,"dataGaName":1157,"dataGaLocation":1158},"search login","search",{"text":1160,"default":1161},"Suggestions",[1162,1164,1168,1170,1174,1178],{"text":840,"config":1163},{"href":845,"dataGaName":840,"dataGaLocation":1158},{"text":1165,"config":1166},"Code Suggestions (AI)",{"href":1167,"dataGaName":1165,"dataGaLocation":1158},"/solutions/code-suggestions/",{"text":365,"config":1169},{"href":877,"dataGaName":365,"dataGaLocation":1158},{"text":1171,"config":1172},"GitLab on AWS",{"href":1173,"dataGaName":1171,"dataGaLocation":1158},"/partners/technology-partners/aws/",{"text":1175,"config":1176},"GitLab on Google Cloud",{"href":1177,"dataGaName":1175,"dataGaLocation":1158},"/partners/technology-partners/google-cloud-platform/",{"text":1179,"config":1180},"Why GitLab?",{"href":853,"dataGaName":1179,"dataGaLocation":1158},{"freeTrial":1182,"mobileIcon":1187,"desktopIcon":1192,"secondaryButton":1195},{"text":1183,"config":1184},"Start free trial",{"href":1185,"dataGaName":814,"dataGaLocation":1186},"https://gitlab.com/-/trials/new/","nav",{"altText":1188,"config":1189},"Gitlab Icon",{"src":1190,"dataGaName":1191,"dataGaLocation":1186},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203874/jypbw1jx72aexsoohd7x.svg","gitlab icon",{"altText":1188,"config":1193},{"src":1194,"dataGaName":1191,"dataGaLocation":1186},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203875/gs4c8p8opsgvflgkswz9.svg",{"text":1196,"config":1197},"Get Started",{"href":1198,"dataGaName":1199,"dataGaLocation":1186},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com/get-started/","get started",{"freeTrial":1201,"mobileIcon":1205,"desktopIcon":1207},{"text":1202,"config":1203},"Learn more about GitLab Duo",{"href":845,"dataGaName":1204,"dataGaLocation":1186},"gitlab duo",{"altText":1188,"config":1206},{"src":1190,"dataGaName":1191,"dataGaLocation":1186},{"altText":1188,"config":1208},{"src":1194,"dataGaName":1191,"dataGaLocation":1186},{"button":1210,"mobileIcon":1215,"desktopIcon":1217},{"text":1211,"config":1212},"/switch",{"href":1213,"dataGaName":1214,"dataGaLocation":1186},"#contact","switch",{"altText":1188,"config":1216},{"src":1190,"dataGaName":1191,"dataGaLocation":1186},{"altText":1188,"config":1218},{"src":1219,"dataGaName":1191,"dataGaLocation":1186},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1773335277/ohhpiuoxoldryzrnhfrh.png",{"freeTrial":1221,"mobileIcon":1226,"desktopIcon":1228},{"text":1222,"config":1223},"Back to pricing",{"href":957,"dataGaName":1224,"dataGaLocation":1186,"icon":1225},"back to pricing","GoBack",{"altText":1188,"config":1227},{"src":1190,"dataGaName":1191,"dataGaLocation":1186},{"altText":1188,"config":1229},{"src":1194,"dataGaName":1191,"dataGaLocation":1186},{"title":1231,"titleMobile":1232,"button":1233,"config":1238},"Duo Agent Platform delivers 400% ROI, per new Forrester Consulting study.","400% ROI: Forrester TEI for GitLab Duo",{"text":851,"config":1234},{"href":1235,"dataGaName":1236,"dataGaLocation":1237},"https://about.gitlab.com/blog/gitlab-duo-agent-platform-delivers-400-percent-roi/","forrester-tei-dap-banner","global-banner",{"layout":1239,"disabled":788},"release",{"data":1241},{"text":1242,"source":1243,"edit":1249,"contribute":1254,"config":1259,"items":1264,"minimal":1474},"Git is a trademark of Software Freedom Conservancy and our use of 'GitLab' is under license",{"text":1244,"config":1245},"View page source",{"href":1246,"dataGaName":1247,"dataGaLocation":1248},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/","page source","footer",{"text":1250,"config":1251},"Edit this page",{"href":1252,"dataGaName":1253,"dataGaLocation":1248},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/content/","web ide",{"text":1255,"config":1256},"Please contribute",{"href":1257,"dataGaName":1258,"dataGaLocation":1248},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/CONTRIBUTING.md/","please contribute",{"twitter":1260,"facebook":1261,"youtube":1262,"linkedin":1263},"https://twitter.com/gitlab","https://www.facebook.com/gitlab","https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg","https://www.linkedin.com/company/gitlab-com",[1265,1312,1366,1410,1442],{"title":955,"links":1266,"subMenu":1281},[1267,1271,1276],{"text":1268,"config":1269},"View plans",{"href":957,"dataGaName":1270,"dataGaLocation":1248},"view plans",{"text":1272,"config":1273},"Why Premium?",{"href":1274,"dataGaName":1275,"dataGaLocation":1248},"/pricing/premium/","why premium",{"text":1277,"config":1278},"Why Ultimate?",{"href":1279,"dataGaName":1280,"dataGaLocation":1248},"/pricing/ultimate/","why ultimate",[1282],{"title":1283,"links":1284},"Contact Us",[1285,1288,1290,1292,1297,1302,1307],{"text":1286,"config":1287},"Contact sales",{"href":1138,"dataGaName":819,"dataGaLocation":1248},{"text":1141,"config":1289},{"href":1143,"dataGaName":1144,"dataGaLocation":1248},{"text":1146,"config":1291},{"href":1148,"dataGaName":1149,"dataGaLocation":1248},{"text":1293,"config":1294},"Status",{"href":1295,"dataGaName":1296,"dataGaLocation":1248},"https://status.gitlab.com/","status",{"text":1298,"config":1299},"Terms of use",{"href":1300,"dataGaName":1301,"dataGaLocation":1248},"/terms/","terms of use",{"text":1303,"config":1304},"Privacy statement",{"href":1305,"dataGaName":1306,"dataGaLocation":1248},"/privacy/","privacy statement",{"text":1308,"config":1309},"Cookie preferences",{"dataGaName":1310,"dataGaLocation":1248,"id":1311,"isOneTrustButton":450},"cookie preferences","ot-sdk-btn",{"title":856,"links":1313,"subMenu":1322},[1314,1318],{"text":1315,"config":1316},"DevSecOps platform",{"href":838,"dataGaName":1317,"dataGaLocation":1248},"devsecops platform",{"text":1319,"config":1320},"AI-Assisted Development",{"href":845,"dataGaName":1321,"dataGaLocation":1248},"ai-assisted development",[1323],{"title":1324,"links":1325},"Topics",[1326,1331,1336,1341,1346,1351,1356,1361],{"text":1327,"config":1328},"CICD",{"href":1329,"dataGaName":1330,"dataGaLocation":1248},"/topics/ci-cd/","cicd",{"text":1332,"config":1333},"GitOps",{"href":1334,"dataGaName":1335,"dataGaLocation":1248},"/topics/gitops/","gitops",{"text":1337,"config":1338},"DevOps",{"href":1339,"dataGaName":1340,"dataGaLocation":1248},"/topics/devops/","devops",{"text":1342,"config":1343},"Version Control",{"href":1344,"dataGaName":1345,"dataGaLocation":1248},"/topics/version-control/","version control",{"text":1347,"config":1348},"DevSecOps",{"href":1349,"dataGaName":1350,"dataGaLocation":1248},"/topics/devsecops/","devsecops",{"text":1352,"config":1353},"Cloud Native",{"href":1354,"dataGaName":1355,"dataGaLocation":1248},"/topics/cloud-native/","cloud native",{"text":1357,"config":1358},"AI for Coding",{"href":1359,"dataGaName":1360,"dataGaLocation":1248},"/topics/devops/ai-for-coding/","ai for coding",{"text":1362,"config":1363},"Agentic AI",{"href":1364,"dataGaName":1365,"dataGaLocation":1248},"/topics/agentic-ai/","agentic ai",{"title":1367,"links":1368},"Solutions",[1369,1371,1373,1378,1382,1385,1389,1392,1394,1397,1400,1405],{"text":899,"config":1370},{"href":894,"dataGaName":899,"dataGaLocation":1248},{"text":888,"config":1372},{"href":872,"dataGaName":873,"dataGaLocation":1248},{"text":1374,"config":1375},"Agile development",{"href":1376,"dataGaName":1377,"dataGaLocation":1248},"/solutions/agile-delivery/","agile delivery",{"text":1379,"config":1380},"SCM",{"href":884,"dataGaName":1381,"dataGaLocation":1248},"source code management",{"text":1327,"config":1383},{"href":877,"dataGaName":1384,"dataGaLocation":1248},"continuous integration & delivery",{"text":1386,"config":1387},"Value stream management",{"href":927,"dataGaName":1388,"dataGaLocation":1248},"value stream management",{"text":1332,"config":1390},{"href":1391,"dataGaName":1335,"dataGaLocation":1248},"/solutions/gitops/",{"text":937,"config":1393},{"href":940,"dataGaName":941,"dataGaLocation":1248},{"text":1395,"config":1396},"Small business",{"href":946,"dataGaName":947,"dataGaLocation":1248},{"text":1398,"config":1399},"Public sector",{"href":952,"dataGaName":953,"dataGaLocation":1248},{"text":1401,"config":1402},"Education",{"href":1403,"dataGaName":1404,"dataGaLocation":1248},"/solutions/education/","education",{"text":1406,"config":1407},"Financial services",{"href":1408,"dataGaName":1409,"dataGaLocation":1248},"/solutions/finance/","financial services",{"title":960,"links":1411},[1412,1414,1416,1418,1421,1423,1426,1428,1430,1432,1434,1436,1438,1440],{"text":973,"config":1413},{"href":975,"dataGaName":976,"dataGaLocation":1248},{"text":978,"config":1415},{"href":980,"dataGaName":981,"dataGaLocation":1248},{"text":983,"config":1417},{"href":985,"dataGaName":986,"dataGaLocation":1248},{"text":988,"config":1419},{"href":990,"dataGaName":1420,"dataGaLocation":1248},"docs",{"text":1010,"config":1422},{"href":1012,"dataGaName":1013,"dataGaLocation":1248},{"text":1424,"config":1425},"What's new",{"href":1070,"dataGaName":1071,"dataGaLocation":1248},{"text":1005,"config":1427},{"href":1007,"dataGaName":1008,"dataGaLocation":1248},{"text":1024,"config":1429},{"href":1026,"dataGaName":1027,"dataGaLocation":1248},{"text":1032,"config":1431},{"href":1034,"dataGaName":1035,"dataGaLocation":1248},{"text":1037,"config":1433},{"href":1039,"dataGaName":1040,"dataGaLocation":1248},{"text":1042,"config":1435},{"href":1044,"dataGaName":1045,"dataGaLocation":1248},{"text":1047,"config":1437},{"href":1049,"dataGaName":1050,"dataGaLocation":1248},{"text":1052,"config":1439},{"href":1054,"dataGaName":1055,"dataGaLocation":1248},{"text":1057,"config":1441},{"href":1059,"dataGaName":1060,"dataGaLocation":1248},{"title":1073,"links":1443},[1444,1446,1448,1450,1452,1454,1458,1463,1465,1467,1469],{"text":1081,"config":1445},{"href":1083,"dataGaName":1075,"dataGaLocation":1248},{"text":1086,"config":1447},{"href":1088,"dataGaName":1089,"dataGaLocation":1248},{"text":1094,"config":1449},{"href":1096,"dataGaName":1097,"dataGaLocation":1248},{"text":1099,"config":1451},{"href":1101,"dataGaName":1102,"dataGaLocation":1248},{"text":1104,"config":1453},{"href":1106,"dataGaName":1107,"dataGaLocation":1248},{"text":1455,"config":1456},"Sustainability",{"href":1457,"dataGaName":1455,"dataGaLocation":1248},"/sustainability/",{"text":1459,"config":1460},"Diversity, inclusion and belonging (DIB)",{"href":1461,"dataGaName":1462,"dataGaLocation":1248},"/diversity-inclusion-belonging/","Diversity, inclusion and belonging",{"text":1109,"config":1464},{"href":1111,"dataGaName":1112,"dataGaLocation":1248},{"text":1119,"config":1466},{"href":1121,"dataGaName":1122,"dataGaLocation":1248},{"text":1124,"config":1468},{"href":1126,"dataGaName":1127,"dataGaLocation":1248},{"text":1470,"config":1471},"Modern Slavery Transparency Statement",{"href":1472,"dataGaName":1473,"dataGaLocation":1248},"https://handbook.gitlab.com/handbook/legal/modern-slavery-act-transparency-statement/","modern slavery transparency statement",{"items":1475},[1476,1479,1482],{"text":1477,"config":1478},"Terms",{"href":1300,"dataGaName":1301,"dataGaLocation":1248},{"text":1480,"config":1481},"Cookies",{"dataGaName":1310,"dataGaLocation":1248,"id":1311,"isOneTrustButton":450},{"text":1483,"config":1484},"Privacy",{"href":1305,"dataGaName":1306,"dataGaLocation":1248},[1486],{"id":1487,"title":7,"body":787,"config":1488,"content":1490,"description":787,"extension":1494,"meta":1495,"navigation":450,"path":1496,"seo":1497,"stem":1498,"__hash__":1499},"blogAuthors/en-us/blog/authors/janis-altherr.yml",{"template":1489},"BlogAuthor",{"name":7,"config":1491},{"headshot":1492,"ctfId":1493},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749663163/Blog/Author%20Headshots/janis-headshot.jpg","janis","yml",{},"/en-us/blog/authors/janis-altherr",{},"en-us/blog/authors/janis-altherr","IypsWlKRRAD566nOfIQF0sRhJjrEm0E-PxjlLJ0XGKE",[1501,1510,1518],{"title":1502,"description":1503,"heroImage":1504,"category":783,"date":1505,"authors":1506,"slug":1509,"externalUrl":787},"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",[1507,1508],"Mathias Ewald","Martin Paloncy, Edgeless Systems","confidential-ai-for-gitlab-self-hosted",{"title":1511,"description":1512,"heroImage":1513,"category":783,"date":1514,"authors":1515,"slug":1517,"externalUrl":787},"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",[1516],"Lysanne Pinto","green-devops-carbon-measurement-cicd-pipeline",{"title":1519,"description":1520,"heroImage":1521,"category":783,"date":1522,"authors":1523,"slug":1525,"externalUrl":787},"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",[1524],"Paul Meresanu","how-to-build-ci-cd-observability-at-scale",{"promotions":1527},[1528,1542,1553,1565],{"id":1529,"categories":1530,"header":1532,"text":1533,"button":1534,"image":1539},"ai-modernization",[1531],"ai","Is AI achieving its promise at scale?","Quiz will take 5 minutes or less",{"text":1535,"config":1536},"Get your AI maturity score",{"href":1537,"dataGaName":1538,"dataGaLocation":1013},"/assessments/ai-modernization-assessment/","modernization assessment",{"config":1540},{"src":1541},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/qix0m7kwnd8x2fh1zq49.png",{"id":1543,"categories":1544,"header":1545,"text":1533,"button":1546,"image":1550},"devops-modernization",[801,1350],"Are you just managing tools or shipping innovation?",{"text":1547,"config":1548},"Get your DevOps maturity score",{"href":1549,"dataGaName":1538,"dataGaLocation":1013},"/assessments/devops-modernization-assessment/",{"config":1551},{"src":1552},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138785/eg818fmakweyuznttgid.png",{"id":1554,"categories":1555,"header":1557,"text":1533,"button":1558,"image":1562},"security-modernization",[1556],"security","Are you trading speed for security?",{"text":1559,"config":1560},"Get your security maturity score",{"href":1561,"dataGaName":1538,"dataGaLocation":1013},"/assessments/security-modernization-assessment/",{"config":1563},{"src":1564},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/p4pbqd9nnjejg5ds6mdk.png",{"id":1566,"paths":1567,"header":1570,"text":1571,"button":1572,"image":1577},"github-azure-migration",[1568,1569],"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":1573,"config":1574},"See how GitLab compares to GitHub",{"href":1575,"dataGaName":1576,"dataGaLocation":1013},"/compare/gitlab-vs-github/github-azure-migration/","github azure migration",{"config":1578},{"src":1552},{"header":1580,"blurb":1581,"button":1582,"secondaryButton":1587},"Start building faster today","See what your team can do with the intelligent orchestration platform for DevSecOps.\n",{"text":1583,"config":1584},"Get your free trial",{"href":1585,"dataGaName":814,"dataGaLocation":1586},"https://gitlab.com/-/trial_registrations/new?glm_content=default-saas-trial&glm_source=about.gitlab.com/","feature",{"text":1286,"config":1588},{"href":1138,"dataGaName":819,"dataGaLocation":1586},1786803746432]