[{"data":1,"prerenderedAt":1354},["ShallowReactive",2],{"/blog/git-performance-on-nfs":3,"navigation-en-us":555,"banner-en-us":983,"footer-en-us":993,"blog-post-authors-en-us-James Ramsay|Zeger-Jan van de Weg":1238,"blog-related-posts-en-us-git-performance-on-nfs":1264,"blog-promotions-en-us":1290,"next-steps-en-us":1344},{"id":4,"title":5,"authors":6,"body":9,"category":535,"date":536,"description":537,"extension":538,"externalUrl":539,"faq":539,"featured":540,"heroImage":541,"meta":542,"navigation":105,"path":543,"seo":544,"slug":548,"stem":549,"tags":550,"template":553,"updatedDate":539,"__hash__":554},"blogPosts/en-us/blog/git-performance-on-nfs.md","What we're doing to fix Gitaly NFS performance regressions",[7,8],"James Ramsay","Zeger-Jan van de Weg",{"type":10,"value":11,"toc":529},"minimark",[12,22,31,36,54,57,251,260,266,271,286,294,306,353,360,412,426,453,463,476,480,493,502,511,525],[13,14,15,16,21],"p",{},"From the start, Gitaly, GitLab's service that is the interface to our Git data,\nfocused on removing the dependency on NFS. We achieved this task at the end\nof the summer 2018, when the ",[17,18,20],"a",{"href":19},"/blog/the-road-to-gitaly-1-0/","NFS drives were unmounted on GitLab.com",".\nThe migration was geared towards improving the availability of Git data at\nGitLab and correctness, that is: fixing bugs. To an extent, performance\nwas an afterthought. By rewriting most of the RPCs in Go there were side effects\nthat positively improved performance, but conversely there were also occasions\nwhere performance wasn't addressed immediately, but rather added to the backlog\nfor the next iteration.",[13,23,24,25,30],{},"Since releasing Gitaly 1.0, and updating GitLab to use Gitaly instead of Rugged\nfor all Git operations, we have observed severe performance regressions for\nlarge GitLab instances when using NFS. To address these performance problems in\nGitLab 11.9, we added ",[17,26,29],{"href":27,"rel":28},"https://docs.gitlab.com/administration/nfs/#improving-nfs-performance-with-gitlab",[],"feature flags"," to enable\nRugged implementations that improve performance for affected GitLab instances.\nThese have been back ported to 11.5-11.8.",[32,33,35],"h3",{"id":34},"so-whats-the-problem","So what's the problem?",[13,37,38,39,44,45,49,50,53],{},"While the migration was under way, there were noticeable performance regressions.\nIn most cases, these were so-called N + 1 access patterns. One example was the\n",[17,40,43],{"href":41,"rel":42},"https://gitlab.com/gitlab-org/gitlab-ce/pipelines/",[],"pipeline index view",", where\neach pipeline runs on a commit. On that page, GitLab used to call the ",[46,47,48],"code",{},"FindCommit","\nRPC for each pipeline. To improve performance, a new RPC was added;\n",[46,51,52],{},"ListCommitsByOid",". In which case, the object IDs for the commits were collected\nfirst, once request was made to Gitaly to get all the commits and return them to\ncontinue rendering the view.",[13,55,56],{},"This approach was, and still is, successful. However, detecting these N + 1\nqueries is hard. When GitLab is run for development as part of the GDK, or\nduring testing, a special N + 1 detector will raise an error if an N + 1\noccurred. This approach has several shortcomings, for one; most tests will only\ntest the behavior of one entity, not 20. This reduces the likelihood of the\nerror being raised. There is also a way to silence N + 1 errors, for example:",[58,59,64],"pre",{"className":60,"code":61,"language":62,"meta":63,"style":63},"language-ruby shiki shiki-themes github-light","project = Project.find(1)\n\nGitalyClient.allow_n_plus_1 do\n  project.pipelines.last(20).each do |pipeline|\n    project.repository.find_commit(pipeline.sha)\n  end\nend\n\n# The better solution would be\n\nshas = project.pipelines.last(20).select(&:sha)\nrepository.list_commits_by_oid(shas)\n","ruby","",[46,65,66,100,107,121,152,174,180,186,191,198,203,239],{"__ignoreMap":63},[67,68,71,75,79,83,87,91,94,97],"span",{"class":69,"line":70},"line",1,[67,72,74],{"class":73},"sqxcx","project",[67,76,78],{"class":77},"sD7c4"," =",[67,80,82],{"class":81},"sYu0t"," Project",[67,84,86],{"class":85},"sgsFI",".",[67,88,90],{"class":89},"s7eDp","find",[67,92,93],{"class":85},"(",[67,95,96],{"class":81},"1",[67,98,99],{"class":85},")\n",[67,101,103],{"class":69,"line":102},2,[67,104,106],{"emptyLinePlaceholder":105},true,"\n",[67,108,110,113,115,118],{"class":69,"line":109},3,[67,111,112],{"class":81},"GitalyClient",[67,114,86],{"class":85},[67,116,117],{"class":89},"allow_n_plus_1",[67,119,120],{"class":77}," do\n",[67,122,124,127,130,132,135,137,140,143,146,149],{"class":69,"line":123},4,[67,125,126],{"class":85},"  project.",[67,128,129],{"class":89},"pipelines",[67,131,86],{"class":85},[67,133,134],{"class":89},"last",[67,136,93],{"class":85},[67,138,139],{"class":81},"20",[67,141,142],{"class":85},").",[67,144,145],{"class":89},"each",[67,147,148],{"class":77}," do",[67,150,151],{"class":85}," |pipeline|\n",[67,153,155,158,161,163,166,169,172],{"class":69,"line":154},5,[67,156,157],{"class":85},"    project.",[67,159,160],{"class":89},"repository",[67,162,86],{"class":85},[67,164,165],{"class":89},"find_commit",[67,167,168],{"class":85},"(pipeline.",[67,170,171],{"class":89},"sha",[67,173,99],{"class":85},[67,175,177],{"class":69,"line":176},6,[67,178,179],{"class":77},"  end\n",[67,181,183],{"class":69,"line":182},7,[67,184,185],{"class":77},"end\n",[67,187,189],{"class":69,"line":188},8,[67,190,106],{"emptyLinePlaceholder":105},[67,192,194],{"class":69,"line":193},9,[67,195,197],{"class":196},"sAwPA","# The better solution would be\n",[67,199,201],{"class":69,"line":200},10,[67,202,106],{"emptyLinePlaceholder":105},[67,204,206,209,211,214,216,218,220,222,224,226,229,231,234,237],{"class":69,"line":205},11,[67,207,208],{"class":73},"shas",[67,210,78],{"class":77},[67,212,213],{"class":85}," project.",[67,215,129],{"class":89},[67,217,86],{"class":85},[67,219,134],{"class":89},[67,221,93],{"class":85},[67,223,139],{"class":81},[67,225,142],{"class":85},[67,227,228],{"class":81},"select",[67,230,93],{"class":85},[67,232,233],{"class":77},"&",[67,235,236],{"class":81},":sha",[67,238,99],{"class":85},[67,240,242,245,248],{"class":69,"line":241},12,[67,243,244],{"class":85},"repository.",[67,246,247],{"class":89},"list_commits_by_oid",[67,249,250],{"class":85},"(shas)\n",[13,252,253,254,259],{},"Whatever happened in that block would not be counted. For each of these blocks\nissues were created and added to ",[17,255,258],{"href":256,"rel":257},"https://gitlab.com/groups/gitlab-org/-/epics/827",[],"an epic",", however, little\nprogress was made by the teams who had bypassed these checks in this way. This\nwas primarily because these performance issues were not a big\nproblem for GitLab.com, despite the fact they had become a problem for our customers.",[13,261,262,263,265],{},"The detected N + 1 issues included a lot of Git object read operations, for\nexample the ",[46,264,48],{}," RPC. This is especially bad because this requires a\nnew Git process to be invoked to fetch each commit. If a millisecond later\nanother request comes in for the same repository, Gitaly will invoke Git again\nand Git will do all this work again. Before the migration and when GitLab.com\nwas still using NFS, GitLab leveraged Rugged, and used memoization to keep around\nthe Rugged Repository until the Rails request was done. This allowed Rugged to\nload part of the Git repository into memory for faster access for subsequent\nrequests. This property was not recreated in Gitaly for some time.",[267,268,270],"h2",{"id":269},"enter-cat-file-cache","Enter cat-file cache",[13,272,273,274,279,280,285],{},"In GitLab 12.1, Gitaly will cache a repository per Rails session to recreate this\nbehavior with a feature called ",[17,275,278],{"href":276,"rel":277},"https://gitlab.com/gitlab-org/gitaly/merge_requests/1203",[],"'cat-file' cache",".\nTo explain how this cache works and its name, it should be noted that objects\nin Git are compressed using ",[17,281,284],{"href":282,"rel":283},"https://www.zlib.net/",[],"zlib",". This means that a commit object\nisn't packed and can be located on disk, it seemingly contains garbage:",[58,287,292],{"className":288,"code":290,"language":291,"meta":63},[289],"language-text","# This example is an empty .gitkeep file\n$ cat .git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391\nxKOR0`\n","text",[46,293,290],{"__ignoreMap":63},[13,295,296,297,300,301,86],{},"Now cat-file will query for the object, and when using the ",[46,298,299],{},"-p"," flag pretty print\nit. In the following example, the current ",[17,302,305],{"href":303,"rel":304},"https://gitlab.com/gitlab-org/gitaly/blob/1b09f13374be5b272d40b3b089372adae2801f81/LICENSE",[],"Gitaly license",[58,307,311],{"className":308,"code":309,"language":310,"meta":63,"style":63},"language-shell shiki shiki-themes github-light","$ git cat-file -p c7344c56da804e88a0bca979a53e1ec1c8b6021e\nThe MIT License (MIT)\n... ommitted\n","shell",[46,312,313,331,345],{"__ignoreMap":63},[67,314,315,318,322,325,328],{"class":69,"line":70},[67,316,317],{"class":89},"$",[67,319,321],{"class":320},"sYBdl"," git",[67,323,324],{"class":320}," cat-file",[67,326,327],{"class":81}," -p",[67,329,330],{"class":320}," c7344c56da804e88a0bca979a53e1ec1c8b6021e\n",[67,332,333,336,339,342],{"class":69,"line":102},[67,334,335],{"class":89},"The",[67,337,338],{"class":320}," MIT",[67,340,341],{"class":320}," License",[67,343,344],{"class":85}," (MIT)\n",[67,346,347,350],{"class":69,"line":109},[67,348,349],{"class":81},"...",[67,351,352],{"class":320}," ommitted\n",[13,354,355,356,359],{},"Cat-file has another flag, ",[46,357,358],{},"--batch",", which allows for multiple objects to be\nrequested to the same process through STDIN.",[58,361,363],{"className":308,"code":362,"language":310,"meta":63,"style":63},"$ git cat-file --batch\nc7344c56da804e88a0bca979a53e1ec1c8b6021e\nc7344c56da804e88a0bca979a53e1ec1c8b6021e blob 1083\nThe MIT License (MIT)\n\n... ommitted\n",[46,364,365,376,381,392,402,406],{"__ignoreMap":63},[67,366,367,369,371,373],{"class":69,"line":70},[67,368,317],{"class":89},[67,370,321],{"class":320},[67,372,324],{"class":320},[67,374,375],{"class":81}," --batch\n",[67,377,378],{"class":69,"line":102},[67,379,380],{"class":89},"c7344c56da804e88a0bca979a53e1ec1c8b6021e\n",[67,382,383,386,389],{"class":69,"line":109},[67,384,385],{"class":89},"c7344c56da804e88a0bca979a53e1ec1c8b6021e",[67,387,388],{"class":320}," blob",[67,390,391],{"class":81}," 1083\n",[67,393,394,396,398,400],{"class":69,"line":123},[67,395,335],{"class":89},[67,397,338],{"class":320},[67,399,341],{"class":320},[67,401,344],{"class":85},[67,403,404],{"class":69,"line":154},[67,405,106],{"emptyLinePlaceholder":105},[67,407,408,410],{"class":69,"line":176},[67,409,349],{"class":81},[67,411,352],{"class":320},[13,413,414,415,420,421,86],{},"Inspecting the Git process using ",[17,416,419],{"href":417,"rel":418},"https://strace.io/",[],"strace"," allows us to inspect how Git\namortizes expensive operations to improve performance. The output on STDOUT and\nthe strace are available ",[17,422,425],{"href":423,"rel":424},"https://gitlab.com/snippets/1858975",[],"as a snippet",[13,427,428,429,434,435,440,441,446,447,452],{},"The process is reading the first input from STDIN, or file descriptor 0, at\n",[17,430,433],{"href":431,"rel":432},"https://gitlab.com/snippets/1858975#L141",[],"line 141",". It starts writing the output\nabout ",[17,436,439],{"href":437,"rel":438},"https://gitlab.com/snippets/1858975#L180",[],"40 syscalls later",". In between\nthere are two important operations performed: an\n",[17,442,445],{"href":443,"rel":444},"https://gitlab.com/snippets/1858975#L167",[],"mmap of the pack file index",", and\nanother ",[17,448,451],{"href":449,"rel":450},"https://gitlab.com/snippets/1858975#L177",[],"mmap of the pack file itself",".\nThese operations store part of these files in memory, so that they are available\nthe next time they are needed.",[13,454,455,456,459,460,462],{},"In the snippet, we've requested the same blob on the same process again. This a\nsyntactic follow-up request, but even when the next request would've been ",[46,457,458],{},"HEAD","\nGit would have to do a considerable amount less work to come up with the object\nthat ",[46,461,458],{}," deferences to.",[13,464,465,466,469,470,475],{},"Keeping a cat-file process around for subsequent requests was shipped in\nGitLab 11.11 behind the ",[46,467,468],{},"gitaly_catfile-cache"," feature flag, and will be\n",[17,471,474],{"href":472,"rel":473},"https://gitlab.com/gitlab-org/gitaly/issues/1671",[],"enabled by default"," in GitLab 12.1.",[32,477,479],{"id":478},"next-steps","Next steps",[13,481,482,483,486,487,492],{},"The ",[46,484,485],{},"cat-file"," cache is one of many improvements being made to improve Git IO\npatterns in GitLab, to mitigate slow IO when using NFS and improve performance\nof GitLab. Particularly, progress has been made in GitLab 11.11, and continues\nto be made in eliminating the worst N + 1 access patterns from GitLab. You can\nfollow ",[17,488,491],{"href":489,"rel":490},"https://gitlab.com/groups/gitlab-org/-/epics/1190",[],"gitlab-org&1190"," for\nthe full plan and progress.",[13,494,495,496,501],{},"The Gitaly team's highest priority is\n",[17,497,500],{"href":498,"rel":499},"https://gitlab.com/gitlab-org/gitlab-ce/issues/60931",[],"automatically enabling Rugged","\nfor GitLab servers using NFS to immediately mitigate the performance\nregressions until performance improvements are sufficiently complete in GitLab\nand Gitaly, allowing Rugged to again be removed.",[13,503,504,505,510],{},"In the future, we will remove the need for NFS with\n",[17,506,509],{"href":507,"rel":508},"https://gitlab.com/groups/gitlab-org/-/epics/842",[],"High Availability for Gitaly",", providing both performance and\navailability, and eliminating the burden of maintaining an NFS cluster.",[13,512,513,514,519,520],{},"Cover image by ",[17,515,518],{"href":516,"rel":517},"https://unsplash.com/@jannesglas",[],"Jannes Glas"," on ",[17,521,524],{"href":522,"rel":523},"https://unsplash.com/photos/P6iOpqQpwwU",[],"Unsplash",[526,527,528],"style",{},"html pre.shiki code .sqxcx, html code.shiki .sqxcx{--shiki-default:#E36209}html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}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 .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}",{"title":63,"searchDepth":102,"depth":102,"links":530},[531,532],{"id":34,"depth":109,"text":35},{"id":269,"depth":102,"text":270,"children":533},[534],{"id":478,"depth":109,"text":479},"engineering","2019-07-08","How we're improving our Git IO patterns to fix performance regressions when running Gitaly on NFS.","md",null,false,"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749670065/Blog/Hero%20Images/git-performance-nfs.jpg",{},"/en-us/blog/git-performance-on-nfs",{"title":5,"description":537,"ogTitle":5,"ogDescription":537,"noIndex":540,"ogImage":541,"ogUrl":545,"ogSiteName":546,"ogType":547,"canonicalUrls":545},"https://about.gitlab.com/blog/git-performance-on-nfs","https://about.gitlab.com","article","git-performance-on-nfs","en-us/blog/git-performance-on-nfs",[551,552],"git","performance","BlogPost","xh2SiSsd6xsRmCoRJrrOAp3Bi91eTDLosI-c4zagG20",{"logo":556,"freeTrial":561,"sales":566,"login":571,"items":576,"search":903,"minimal":934,"duo":953,"switchNav":962,"pricingDeployment":973},{"config":557},{"href":558,"dataGaName":559,"dataGaLocation":560},"/","gitlab logo","header",{"text":562,"config":563},"Get free trial",{"href":564,"dataGaName":565,"dataGaLocation":560},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com&glm_content=default-saas-trial/","free trial",{"text":567,"config":568},"Request a demo",{"href":569,"dataGaName":570,"dataGaLocation":560},"/sales/?contact-topic=request-demo","sales",{"text":572,"config":573},"Sign in",{"href":574,"dataGaName":575,"dataGaLocation":560},"https://gitlab.com/users/sign_in/","sign in",[577,606,706,711,825,881],{"text":578,"config":579,"menu":581},"Platform",{"dataNavLevelOne":580},"platform",{"type":582,"columns":583},"cards",[584,590,598],{"title":578,"description":585,"link":586},"The intelligent orchestration platform for DevSecOps",{"text":587,"config":588},"Explore our Platform",{"href":589,"dataGaName":580,"dataGaLocation":560},"/platform/",{"title":591,"description":592,"link":593},"GitLab Duo Agent Platform","Agentic AI for the entire software lifecycle",{"text":594,"config":595},"Meet GitLab Duo",{"href":596,"dataGaName":597,"dataGaLocation":560},"/gitlab-duo-agent-platform/","gitlab duo agent platform",{"title":599,"description":600,"link":601},"Why GitLab","See the top reasons enterprises choose GitLab",{"text":602,"config":603},"Learn more",{"href":604,"dataGaName":605,"dataGaLocation":560},"/why-gitlab/","why gitlab",{"text":607,"left":105,"config":608,"menu":610},"Product",{"dataNavLevelOne":609},"solutions",{"type":611,"link":612,"columns":616,"feature":685},"lists",{"text":613,"config":614},"View all Solutions",{"href":615,"dataGaName":609,"dataGaLocation":560},"/solutions/",[617,641,664],{"title":618,"description":619,"link":620,"items":625},"Automation","CI/CD and automation to accelerate deployment",{"config":621},{"icon":622,"href":623,"dataGaName":624,"dataGaLocation":560},"AutomatedCodeAlt","/solutions/delivery-automation/","automated software delivery",[626,630,633,637],{"text":627,"config":628},"CI/CD",{"href":629,"dataGaLocation":560,"dataGaName":627},"/solutions/continuous-integration/",{"text":591,"config":631},{"href":596,"dataGaLocation":560,"dataGaName":632},"gitlab duo agent platform - product menu",{"text":634,"config":635},"Source Code Management",{"href":636,"dataGaLocation":560,"dataGaName":634},"/solutions/source-code-management/",{"text":638,"config":639},"Automated Software Delivery",{"href":623,"dataGaLocation":560,"dataGaName":640},"Automated software delivery",{"title":642,"description":643,"link":644,"items":649},"Security","Deliver code faster without compromising security",{"config":645},{"href":646,"dataGaName":647,"dataGaLocation":560,"icon":648},"/solutions/application-security-testing/","security and compliance","ShieldCheckLight",[650,654,659],{"text":651,"config":652},"Application Security Testing",{"href":646,"dataGaName":653,"dataGaLocation":560},"Application security testing",{"text":655,"config":656},"Software Supply Chain Security",{"href":657,"dataGaLocation":560,"dataGaName":658},"/solutions/supply-chain/","Software supply chain security",{"text":660,"config":661},"Software Compliance",{"href":662,"dataGaName":663,"dataGaLocation":560},"/solutions/software-compliance/","software compliance",{"title":665,"link":666,"items":671},"Measurement",{"config":667},{"icon":668,"href":669,"dataGaName":670,"dataGaLocation":560},"DigitalTransformation","/solutions/visibility-measurement/","visibility and measurement",[672,676,680],{"text":673,"config":674},"Visibility & Measurement",{"href":669,"dataGaLocation":560,"dataGaName":675},"Visibility and Measurement",{"text":677,"config":678},"Value Stream Management",{"href":679,"dataGaLocation":560,"dataGaName":677},"/solutions/value-stream-management/",{"text":681,"config":682},"Analytics & Insights",{"href":683,"dataGaLocation":560,"dataGaName":684},"/solutions/analytics-and-insights/","Analytics and insights",{"title":686,"type":611,"items":687},"GitLab for",[688,694,700],{"text":689,"config":690},"Enterprise",{"icon":691,"href":692,"dataGaLocation":560,"dataGaName":693},"Building","/enterprise/","enterprise",{"text":695,"config":696},"Small Business",{"icon":697,"href":698,"dataGaLocation":560,"dataGaName":699},"Work","/small-business/","small business",{"text":701,"config":702},"Public Sector",{"icon":703,"href":704,"dataGaLocation":560,"dataGaName":705},"Organization","/solutions/public-sector/","public sector",{"text":707,"config":708},"Pricing",{"href":709,"dataGaName":710,"dataGaLocation":560,"dataNavLevelOne":710},"/pricing/","pricing",{"text":712,"config":713,"menu":715},"Resources",{"dataNavLevelOne":714},"resources",{"type":611,"link":716,"columns":720,"feature":814},{"text":717,"config":718},"View all resources",{"href":719,"dataGaName":714,"dataGaLocation":560},"/resources/",[721,754,781],{"title":722,"items":723},"Getting started",[724,729,734,739,744,749],{"text":725,"config":726},"Install",{"href":727,"dataGaName":728,"dataGaLocation":560},"/install/","install",{"text":730,"config":731},"Quick start guides",{"href":732,"dataGaName":733,"dataGaLocation":560},"/get-started/","quick setup checklists",{"text":735,"config":736},"Learn",{"href":737,"dataGaLocation":560,"dataGaName":738},"https://university.gitlab.com/","learn",{"text":740,"config":741},"Product documentation",{"href":742,"dataGaName":743,"dataGaLocation":560},"https://docs.gitlab.com/","product documentation",{"text":745,"config":746},"Best practice videos",{"href":747,"dataGaName":748,"dataGaLocation":560},"/getting-started-videos/","best practice videos",{"text":750,"config":751},"Integrations",{"href":752,"dataGaName":753,"dataGaLocation":560},"/integrations/","integrations",{"title":755,"items":756},"Discover",[757,762,767,772,776],{"text":758,"config":759},"Customer success stories",{"href":760,"dataGaName":761,"dataGaLocation":560},"/customers/","customer success stories",{"text":763,"config":764},"Blog",{"href":765,"dataGaName":766,"dataGaLocation":560},"/blog/","blog",{"text":768,"config":769},"Demo Hub",{"href":770,"dataGaName":771,"dataGaLocation":560},"/demo-hub/","demo hub",{"text":773,"config":774},"The Source",{"href":775,"dataGaName":766,"dataGaLocation":560},"/the-source/",{"text":777,"config":778},"Remote",{"href":779,"dataGaName":780,"dataGaLocation":560},"https://handbook.gitlab.com/handbook/company/culture/all-remote/","remote",{"title":782,"items":783},"Connect",[784,789,794,799,804,809],{"text":785,"config":786},"GitLab Services",{"href":787,"dataGaName":788,"dataGaLocation":560},"/services/","services",{"text":790,"config":791},"Contribute",{"href":792,"dataGaName":793,"dataGaLocation":560},"https://contributors.gitlab.com","contribute",{"text":795,"config":796},"Community",{"href":797,"dataGaName":798,"dataGaLocation":560},"/community/","community",{"text":800,"config":801},"Forum",{"href":802,"dataGaName":803,"dataGaLocation":560},"https://forum.gitlab.com/","forum",{"text":805,"config":806},"Events",{"href":807,"dataGaName":808,"dataGaLocation":560},"/events/","events",{"text":810,"config":811},"Partners",{"href":812,"dataGaName":813,"dataGaLocation":560},"/partners/","partners",{"config":815,"title":818,"text":819,"link":820},{"background":816,"textColor":817},"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":821,"config":822},"Read the latest",{"href":823,"dataGaName":824,"dataGaLocation":560},"/whats-new/","whats new",{"text":826,"config":827,"menu":829},"Company",{"dataNavLevelOne":828},"company",{"type":611,"columns":830},[831],{"items":832},[833,838,844,846,851,856,861,866,871,876],{"text":834,"config":835},"About",{"href":836,"dataGaName":837,"dataGaLocation":560},"/company/","about",{"text":839,"config":840,"footerGa":843},"Jobs",{"href":841,"dataGaName":842,"dataGaLocation":560},"/jobs/","jobs",{"dataGaName":842},{"text":805,"config":845},{"href":807,"dataGaName":808,"dataGaLocation":560},{"text":847,"config":848},"Leadership",{"href":849,"dataGaName":850,"dataGaLocation":560},"/company/team/e-group/","leadership",{"text":852,"config":853},"Handbook",{"href":854,"dataGaName":855,"dataGaLocation":560},"https://handbook.gitlab.com/","handbook",{"text":857,"config":858},"Investor relations",{"href":859,"dataGaName":860,"dataGaLocation":560},"https://ir.gitlab.com/overview/default.aspx","investor relations",{"text":862,"config":863},"Trust Center",{"href":864,"dataGaName":865,"dataGaLocation":560},"/security/","trust center",{"text":867,"config":868},"AI Transparency Center",{"href":869,"dataGaName":870,"dataGaLocation":560},"/ai-transparency-center/","ai transparency center",{"text":872,"config":873},"Newsletter",{"href":874,"dataGaName":875,"dataGaLocation":560},"/company/contact/#contact-forms","newsletter",{"text":877,"config":878},"Press",{"href":879,"dataGaName":880,"dataGaLocation":560},"/press/","press",{"text":882,"config":883,"menu":884},"Contact us",{"dataNavLevelOne":828},{"type":611,"columns":885},[886],{"items":887},[888,893,898],{"text":889,"config":890},"Talk to sales",{"href":891,"dataGaName":892,"dataGaLocation":560},"/sales/","talk to sales",{"text":894,"config":895},"Support portal",{"href":896,"dataGaName":897,"dataGaLocation":560},"https://support.gitlab.com/hc/en-us","support portal",{"text":899,"config":900},"Customer portal",{"href":901,"dataGaName":902,"dataGaLocation":560},"https://customers.gitlab.com/customers/sign_in/","customer portal",{"close":904,"login":905,"suggestions":912},"Close",{"text":906,"link":907},"To search repositories and projects, login to",{"text":908,"config":909},"gitlab.com",{"href":574,"dataGaName":910,"dataGaLocation":911},"search login","search",{"text":913,"default":914},"Suggestions",[915,917,921,923,927,931],{"text":591,"config":916},{"href":596,"dataGaName":591,"dataGaLocation":911},{"text":918,"config":919},"Code Suggestions (AI)",{"href":920,"dataGaName":918,"dataGaLocation":911},"/solutions/code-suggestions/",{"text":627,"config":922},{"href":629,"dataGaName":627,"dataGaLocation":911},{"text":924,"config":925},"GitLab on AWS",{"href":926,"dataGaName":924,"dataGaLocation":911},"/partners/technology-partners/aws/",{"text":928,"config":929},"GitLab on Google Cloud",{"href":930,"dataGaName":928,"dataGaLocation":911},"/partners/technology-partners/google-cloud-platform/",{"text":932,"config":933},"Why GitLab?",{"href":604,"dataGaName":932,"dataGaLocation":911},{"freeTrial":935,"mobileIcon":940,"desktopIcon":945,"secondaryButton":948},{"text":936,"config":937},"Start free trial",{"href":938,"dataGaName":565,"dataGaLocation":939},"https://gitlab.com/-/trials/new/","nav",{"altText":941,"config":942},"Gitlab Icon",{"src":943,"dataGaName":944,"dataGaLocation":939},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203874/jypbw1jx72aexsoohd7x.svg","gitlab icon",{"altText":941,"config":946},{"src":947,"dataGaName":944,"dataGaLocation":939},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203875/gs4c8p8opsgvflgkswz9.svg",{"text":949,"config":950},"Get Started",{"href":951,"dataGaName":952,"dataGaLocation":939},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com/get-started/","get started",{"freeTrial":954,"mobileIcon":958,"desktopIcon":960},{"text":955,"config":956},"Learn more about GitLab Duo",{"href":596,"dataGaName":957,"dataGaLocation":939},"gitlab duo",{"altText":941,"config":959},{"src":943,"dataGaName":944,"dataGaLocation":939},{"altText":941,"config":961},{"src":947,"dataGaName":944,"dataGaLocation":939},{"button":963,"mobileIcon":968,"desktopIcon":970},{"text":964,"config":965},"/switch",{"href":966,"dataGaName":967,"dataGaLocation":939},"#contact","switch",{"altText":941,"config":969},{"src":943,"dataGaName":944,"dataGaLocation":939},{"altText":941,"config":971},{"src":972,"dataGaName":944,"dataGaLocation":939},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1773335277/ohhpiuoxoldryzrnhfrh.png",{"freeTrial":974,"mobileIcon":979,"desktopIcon":981},{"text":975,"config":976},"Back to pricing",{"href":709,"dataGaName":977,"dataGaLocation":939,"icon":978},"back to pricing","GoBack",{"altText":941,"config":980},{"src":943,"dataGaName":944,"dataGaLocation":939},{"altText":941,"config":982},{"src":947,"dataGaName":944,"dataGaLocation":939},{"title":984,"titleMobile":985,"button":986,"config":991},"Duo Agent Platform delivers 400% ROI, per new Forrester Consulting study.","400% ROI: Forrester TEI for GitLab Duo",{"text":602,"config":987},{"href":988,"dataGaName":989,"dataGaLocation":990},"https://about.gitlab.com/blog/gitlab-duo-agent-platform-delivers-400-percent-roi/","forrester-tei-dap-banner","global-banner",{"layout":992,"disabled":540},"release",{"data":994},{"text":995,"source":996,"edit":1002,"contribute":1007,"config":1012,"items":1017,"minimal":1227},"Git is a trademark of Software Freedom Conservancy and our use of 'GitLab' is under license",{"text":997,"config":998},"View page source",{"href":999,"dataGaName":1000,"dataGaLocation":1001},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/","page source","footer",{"text":1003,"config":1004},"Edit this page",{"href":1005,"dataGaName":1006,"dataGaLocation":1001},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/content/","web ide",{"text":1008,"config":1009},"Please contribute",{"href":1010,"dataGaName":1011,"dataGaLocation":1001},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/CONTRIBUTING.md/","please contribute",{"twitter":1013,"facebook":1014,"youtube":1015,"linkedin":1016},"https://twitter.com/gitlab","https://www.facebook.com/gitlab","https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg","https://www.linkedin.com/company/gitlab-com",[1018,1065,1119,1163,1195],{"title":707,"links":1019,"subMenu":1034},[1020,1024,1029],{"text":1021,"config":1022},"View plans",{"href":709,"dataGaName":1023,"dataGaLocation":1001},"view plans",{"text":1025,"config":1026},"Why Premium?",{"href":1027,"dataGaName":1028,"dataGaLocation":1001},"/pricing/premium/","why premium",{"text":1030,"config":1031},"Why Ultimate?",{"href":1032,"dataGaName":1033,"dataGaLocation":1001},"/pricing/ultimate/","why ultimate",[1035],{"title":1036,"links":1037},"Contact Us",[1038,1041,1043,1045,1050,1055,1060],{"text":1039,"config":1040},"Contact sales",{"href":891,"dataGaName":570,"dataGaLocation":1001},{"text":894,"config":1042},{"href":896,"dataGaName":897,"dataGaLocation":1001},{"text":899,"config":1044},{"href":901,"dataGaName":902,"dataGaLocation":1001},{"text":1046,"config":1047},"Status",{"href":1048,"dataGaName":1049,"dataGaLocation":1001},"https://status.gitlab.com/","status",{"text":1051,"config":1052},"Terms of use",{"href":1053,"dataGaName":1054,"dataGaLocation":1001},"/terms/","terms of use",{"text":1056,"config":1057},"Privacy statement",{"href":1058,"dataGaName":1059,"dataGaLocation":1001},"/privacy/","privacy statement",{"text":1061,"config":1062},"Cookie preferences",{"dataGaName":1063,"dataGaLocation":1001,"id":1064,"isOneTrustButton":105},"cookie preferences","ot-sdk-btn",{"title":607,"links":1066,"subMenu":1075},[1067,1071],{"text":1068,"config":1069},"DevSecOps platform",{"href":589,"dataGaName":1070,"dataGaLocation":1001},"devsecops platform",{"text":1072,"config":1073},"AI-Assisted Development",{"href":596,"dataGaName":1074,"dataGaLocation":1001},"ai-assisted development",[1076],{"title":1077,"links":1078},"Topics",[1079,1084,1089,1094,1099,1104,1109,1114],{"text":1080,"config":1081},"CICD",{"href":1082,"dataGaName":1083,"dataGaLocation":1001},"/topics/ci-cd/","cicd",{"text":1085,"config":1086},"GitOps",{"href":1087,"dataGaName":1088,"dataGaLocation":1001},"/topics/gitops/","gitops",{"text":1090,"config":1091},"DevOps",{"href":1092,"dataGaName":1093,"dataGaLocation":1001},"/topics/devops/","devops",{"text":1095,"config":1096},"Version Control",{"href":1097,"dataGaName":1098,"dataGaLocation":1001},"/topics/version-control/","version control",{"text":1100,"config":1101},"DevSecOps",{"href":1102,"dataGaName":1103,"dataGaLocation":1001},"/topics/devsecops/","devsecops",{"text":1105,"config":1106},"Cloud Native",{"href":1107,"dataGaName":1108,"dataGaLocation":1001},"/topics/cloud-native/","cloud native",{"text":1110,"config":1111},"AI for Coding",{"href":1112,"dataGaName":1113,"dataGaLocation":1001},"/topics/devops/ai-for-coding/","ai for coding",{"text":1115,"config":1116},"Agentic AI",{"href":1117,"dataGaName":1118,"dataGaLocation":1001},"/topics/agentic-ai/","agentic ai",{"title":1120,"links":1121},"Solutions",[1122,1124,1126,1131,1135,1138,1142,1145,1147,1150,1153,1158],{"text":651,"config":1123},{"href":646,"dataGaName":651,"dataGaLocation":1001},{"text":640,"config":1125},{"href":623,"dataGaName":624,"dataGaLocation":1001},{"text":1127,"config":1128},"Agile development",{"href":1129,"dataGaName":1130,"dataGaLocation":1001},"/solutions/agile-delivery/","agile delivery",{"text":1132,"config":1133},"SCM",{"href":636,"dataGaName":1134,"dataGaLocation":1001},"source code management",{"text":1080,"config":1136},{"href":629,"dataGaName":1137,"dataGaLocation":1001},"continuous integration & delivery",{"text":1139,"config":1140},"Value stream management",{"href":679,"dataGaName":1141,"dataGaLocation":1001},"value stream management",{"text":1085,"config":1143},{"href":1144,"dataGaName":1088,"dataGaLocation":1001},"/solutions/gitops/",{"text":689,"config":1146},{"href":692,"dataGaName":693,"dataGaLocation":1001},{"text":1148,"config":1149},"Small business",{"href":698,"dataGaName":699,"dataGaLocation":1001},{"text":1151,"config":1152},"Public sector",{"href":704,"dataGaName":705,"dataGaLocation":1001},{"text":1154,"config":1155},"Education",{"href":1156,"dataGaName":1157,"dataGaLocation":1001},"/solutions/education/","education",{"text":1159,"config":1160},"Financial services",{"href":1161,"dataGaName":1162,"dataGaLocation":1001},"/solutions/finance/","financial services",{"title":712,"links":1164},[1165,1167,1169,1171,1174,1176,1179,1181,1183,1185,1187,1189,1191,1193],{"text":725,"config":1166},{"href":727,"dataGaName":728,"dataGaLocation":1001},{"text":730,"config":1168},{"href":732,"dataGaName":733,"dataGaLocation":1001},{"text":735,"config":1170},{"href":737,"dataGaName":738,"dataGaLocation":1001},{"text":740,"config":1172},{"href":742,"dataGaName":1173,"dataGaLocation":1001},"docs",{"text":763,"config":1175},{"href":765,"dataGaName":766,"dataGaLocation":1001},{"text":1177,"config":1178},"What's new",{"href":823,"dataGaName":824,"dataGaLocation":1001},{"text":758,"config":1180},{"href":760,"dataGaName":761,"dataGaLocation":1001},{"text":777,"config":1182},{"href":779,"dataGaName":780,"dataGaLocation":1001},{"text":785,"config":1184},{"href":787,"dataGaName":788,"dataGaLocation":1001},{"text":790,"config":1186},{"href":792,"dataGaName":793,"dataGaLocation":1001},{"text":795,"config":1188},{"href":797,"dataGaName":798,"dataGaLocation":1001},{"text":800,"config":1190},{"href":802,"dataGaName":803,"dataGaLocation":1001},{"text":805,"config":1192},{"href":807,"dataGaName":808,"dataGaLocation":1001},{"text":810,"config":1194},{"href":812,"dataGaName":813,"dataGaLocation":1001},{"title":826,"links":1196},[1197,1199,1201,1203,1205,1207,1211,1216,1218,1220,1222],{"text":834,"config":1198},{"href":836,"dataGaName":828,"dataGaLocation":1001},{"text":839,"config":1200},{"href":841,"dataGaName":842,"dataGaLocation":1001},{"text":847,"config":1202},{"href":849,"dataGaName":850,"dataGaLocation":1001},{"text":852,"config":1204},{"href":854,"dataGaName":855,"dataGaLocation":1001},{"text":857,"config":1206},{"href":859,"dataGaName":860,"dataGaLocation":1001},{"text":1208,"config":1209},"Sustainability",{"href":1210,"dataGaName":1208,"dataGaLocation":1001},"/sustainability/",{"text":1212,"config":1213},"Diversity, inclusion and belonging (DIB)",{"href":1214,"dataGaName":1215,"dataGaLocation":1001},"/diversity-inclusion-belonging/","Diversity, inclusion and belonging",{"text":862,"config":1217},{"href":864,"dataGaName":865,"dataGaLocation":1001},{"text":872,"config":1219},{"href":874,"dataGaName":875,"dataGaLocation":1001},{"text":877,"config":1221},{"href":879,"dataGaName":880,"dataGaLocation":1001},{"text":1223,"config":1224},"Modern Slavery Transparency Statement",{"href":1225,"dataGaName":1226,"dataGaLocation":1001},"https://handbook.gitlab.com/handbook/legal/modern-slavery-act-transparency-statement/","modern slavery transparency statement",{"items":1228},[1229,1232,1235],{"text":1230,"config":1231},"Terms",{"href":1053,"dataGaName":1054,"dataGaLocation":1001},{"text":1233,"config":1234},"Cookies",{"dataGaName":1063,"dataGaLocation":1001,"id":1064,"isOneTrustButton":105},{"text":1236,"config":1237},"Privacy",{"href":1058,"dataGaName":1059,"dataGaLocation":1001},[1239,1252],{"id":1240,"title":7,"body":539,"config":1241,"content":1243,"description":539,"extension":1246,"meta":1247,"navigation":105,"path":1248,"seo":1249,"stem":1250,"__hash__":1251},"blogAuthors/en-us/blog/authors/james-ramsay.yml",{"template":1242},"BlogAuthor",{"name":7,"config":1244},{"headshot":63,"ctfId":1245},"jramsay","yml",{},"/en-us/blog/authors/james-ramsay",{},"en-us/blog/authors/james-ramsay","iKU7kqEnGoklxsvYnqw2L7oAOICkVwJOVHAkOv_GdM4",{"id":1253,"title":1254,"body":539,"config":1255,"content":1256,"description":539,"extension":1246,"meta":1259,"navigation":105,"path":1260,"seo":1261,"stem":1262,"__hash__":1263},"blogAuthors/en-us/blog/authors/zeger-jan-van-de-weg.yml","Zeger Jan Van De Weg",{"template":1242},{"name":8,"config":1257},{"headshot":63,"ctfId":1258},"zjgitlab",{},"/en-us/blog/authors/zeger-jan-van-de-weg",{},"en-us/blog/authors/zeger-jan-van-de-weg","uTVQwXNnBL0ibdUCEMyi-YCRI3IJbCiLvsRdKDbliM8",[1265,1274,1282],{"title":1266,"description":1267,"heroImage":1268,"category":535,"date":1269,"authors":1270,"slug":1273,"externalUrl":539},"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",[1271,1272],"Mathias Ewald","Martin Paloncy, Edgeless Systems","confidential-ai-for-gitlab-self-hosted",{"title":1275,"description":1276,"heroImage":1277,"category":535,"date":1278,"authors":1279,"slug":1281,"externalUrl":539},"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",[1280],"Lysanne Pinto","green-devops-carbon-measurement-cicd-pipeline",{"title":1283,"description":1284,"heroImage":1285,"category":535,"date":1286,"authors":1287,"slug":1289,"externalUrl":539},"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",[1288],"Paul Meresanu","how-to-build-ci-cd-observability-at-scale",{"promotions":1291},[1292,1306,1318,1330],{"id":1293,"categories":1294,"header":1296,"text":1297,"button":1298,"image":1303},"ai-modernization",[1295],"ai","Is AI achieving its promise at scale?","Quiz will take 5 minutes or less",{"text":1299,"config":1300},"Get your AI maturity score",{"href":1301,"dataGaName":1302,"dataGaLocation":766},"/assessments/ai-modernization-assessment/","modernization assessment",{"config":1304},{"src":1305},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/qix0m7kwnd8x2fh1zq49.png",{"id":1307,"categories":1308,"header":1310,"text":1297,"button":1311,"image":1315},"devops-modernization",[1309,1103],"product","Are you just managing tools or shipping innovation?",{"text":1312,"config":1313},"Get your DevOps maturity score",{"href":1314,"dataGaName":1302,"dataGaLocation":766},"/assessments/devops-modernization-assessment/",{"config":1316},{"src":1317},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138785/eg818fmakweyuznttgid.png",{"id":1319,"categories":1320,"header":1322,"text":1297,"button":1323,"image":1327},"security-modernization",[1321],"security","Are you trading speed for security?",{"text":1324,"config":1325},"Get your security maturity score",{"href":1326,"dataGaName":1302,"dataGaLocation":766},"/assessments/security-modernization-assessment/",{"config":1328},{"src":1329},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/p4pbqd9nnjejg5ds6mdk.png",{"id":1331,"paths":1332,"header":1335,"text":1336,"button":1337,"image":1342},"github-azure-migration",[1333,1334],"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":1338,"config":1339},"See how GitLab compares to GitHub",{"href":1340,"dataGaName":1341,"dataGaLocation":766},"/compare/gitlab-vs-github/github-azure-migration/","github azure migration",{"config":1343},{"src":1317},{"header":1345,"blurb":1346,"button":1347,"secondaryButton":1352},"Start building faster today","See what your team can do with the intelligent orchestration platform for DevSecOps.\n",{"text":1348,"config":1349},"Get your free trial",{"href":1350,"dataGaName":565,"dataGaLocation":1351},"https://gitlab.com/-/trial_registrations/new?glm_content=default-saas-trial&glm_source=about.gitlab.com/","feature",{"text":1039,"config":1353},{"href":891,"dataGaName":570,"dataGaLocation":1351},1786803747464]