[{"data":1,"prerenderedAt":1412},["ShallowReactive",2],{"/blog/vue-big-plan":3,"navigation-en-us":627,"banner-en-us":1054,"footer-en-us":1064,"blog-post-authors-en-us-Jacob Schatz":1308,"blog-related-posts-en-us-vue-big-plan":1322,"blog-promotions-en-us":1348,"next-steps-en-us":1402},{"id":4,"title":5,"authors":6,"body":8,"category":605,"date":606,"description":607,"extension":608,"externalUrl":609,"faq":609,"featured":610,"heroImage":611,"meta":612,"navigation":617,"path":618,"seo":619,"slug":623,"stem":624,"tags":609,"template":625,"updatedDate":609,"__hash__":626},"blogPosts/en-us/blog/vue-big-plan.md","Our big Frontend plan revealed",[7],"Jacob Schatz",{"type":9,"value":10,"toc":596},"minimark",[11,15,52,57,70,83,86,89,93,96,101,104,107,110,143,146,150,170,179,307,320,324,339,344,355,359,374,377,380,468,475,479,482,563,566,570,573,577,580,583,592],[12,13,14],"p",{},"The Frontend at GitLab is getting better and better every day. Today we did two big things, and I'd like to share them with you and our big plans for the future.",[16,17,19],"blockquote",{"style":18},"color: red",[20,21,22,23,22,27,22,36,22,44],"ul",{},"\n  ",[24,25,26],"li",{},"If you use the GDK, then make sure you update it! If you have no idea what I am talking about, then just keep reading.",[24,28,29,30,35],{},"Please see the ",[31,32,34],"a",{"href":33},"https://gitlab.com/gitlab-org/gitlab-development-kit/blob/master/doc/update-gdk.md","documentation"," for instructions on updating your GDK.",[24,37,38,39,43],{},"Please see our ",[31,40,42],{"href":41},"https://gitlab.com/gitlab-org/gitlab-development-kit/blob/master/doc/howto/troubleshooting.md#webpack","troubleshooting guide"," for any issues when updating your GDK.",[24,45,46,47,51],{},"Feel free to ",[31,48,50],{"href":49},"https://gitlab.com/gitlab-org/gitlab-ce/issues/new","report"," any additional issues you find.",[53,54,56],"h2",{"id":55},"our-big-frontend-plan","Our big Frontend plan",[12,58,59,64,65,69],{},[31,60,63],{"href":61,"rel":62},"https://vuejs.org/",[],"Vue"," is awesome. I wrote an article a while ago that showed ",[31,66,68],{"href":67},"/blog/why-we-chose-vue/","GitLab's love for Vue",". Today's article is a way to show our plan over the long term to make GitLab as fast and performant as possible with Vue and webpack. We want to make GitLab the easiest to develop for Frontend Developers.",[12,71,72,73,77,78,82],{},"One of the lessons I live by is \"It's not ",[74,75,76],"em",{},"always"," about the tools you use, but ",[79,80,81],"strong",{},"how"," you use them.\"  Saying \"we chose Vue\", does not imply success. This also means that we could be using Angular or React and have just as awesome of a product. Vue is simply the way there.",[12,84,85],{},"How do we plan to use Vue over the long run to make GitLab better, faster, easier and more awesome?",[12,87,88],{},"The plan below is a work in progress and very ambitious, but I believe that it will result in a much better frontend for development and performance. This document is also a reference to myself of the things we plan to do here at GitLab's Frontend.",[53,90,92],{"id":91},"a-healthier-frontend","A healthier Frontend",[12,94,95],{},"When I started at GitLab, our stack was (oversimplifying here) Rails with jQuery. It hasn't changed much big picture wise except for Vue. Smaller picture, we've added many linters, better code coverage, and many other great things.",[97,98,100],"h3",{"id":99},"_1-rewrite-only-what-you-need-to","1. Rewrite only what you need to",[12,102,103],{},"We are not rewriting GitLab's frontend entirely in Vue. That would be a very bad idea. It's not a bad idea for everyone, but it's a bad idea for a startup. It would cost a tremendous amount of time and money. The existing jQuery code (although some say is uncool) has been tested and works very well. There is no need to rewrite functionality that works well, unless there is going to be a major gain.",[12,105,106],{},"We also aren't writing every new thing in Vue. You do not need to do this either. But, it would be hard to find some part of the UI that would not benefit from even the simplest parts of Vue.",[12,108,109],{},"Examples of this are:",[111,112,113,116,131,134,137,140],"ol",{},[24,114,115],{},"The issue page (which shows an individual issue), has a lot of jQuery on it. We won't rewrite now, because it works well. We will rewrite small parts in Vue once we make certain features more real-time. We are currently making the title and description real time.",[24,117,118,119,124,125,130],{},"The ",[31,120,123],{"href":121,"rel":122},"https://docs.gitlab.com/user/project/issue_board/",[],"Issue Boards",", which ",[31,126,129],{"href":127,"rel":128},"https://twitter.com/iamphill",[],"Phil"," wrote, was a perfect candidate for Vue. It was a brand new feature and had lots of reactive parts.",[24,132,133],{},"The current issue page loads all comments at once and adds lots of event listeners to the page. This page could benefit from Vue for performance reasons. We could make the comment section a Vue app and make the comments a component with the emoji picker as components as well, etc. While we're in there, we'll amp up the UX by allowing you to see the comment you linked to immediately without waiting. There are better ways to show massive amounts of comments so we have to potentially rethink that.",[24,135,136],{},"The pipelines page rewritten in vue for the arrival of real time updating.",[24,138,139],{},"The environments was written in Vue.",[24,141,142],{},"There are many other places where we will be using Vue in the future and where we are already using Vue. Too many to list here.",[12,144,145],{},"As you can see, we won't just slap Vue on everything.",[97,147,149],{"id":148},"_2-add-in-webpack","2. Add in webpack",[12,151,152,153,157,158,161,162,165,166,169],{},"Rails has this awesome system of grabbing your Ruby libraries and bundling them into your app. ",[154,155,156],"code",{},"bundle install"," will install all the stuff you need from your ",[154,159,160],{},"Gemfile",". So why does Frontend have to stick all their libraries in the ",[154,163,164],{},"vendor"," directory? Are we not on point enough to have our own library delivery system? The javascript ecosystem has matured since the asset pipeline first arrived, and we now have ",[154,167,168],{},"npm install"," and advanced code bundling tools that we can take advantage of.",[12,171,172,173,178],{},"By ",[31,174,177],{"href":175,"rel":176},"https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7288",[],"introducing webpack into the equation (merged and ready for action!)"," we gain multiple benefits.",[111,180,181,197,212,221,224,249,252,261,281,292],{},[24,182,183,184,188,189,192,193,196],{},"Javascript libraries aren't being bundled directly with the ",[31,185,187],{"href":186},"/solutions/source-code-management/","GitLab source code"," or included within gem wrappers. e.g. ",[154,190,191],{},"jquery-ui"," or ",[154,194,195],{},"bootstrap-rails"," are included as a ruby gem and we are at the mercy of the gem maintainer to keep the Javascript library up to date.",[24,198,199,200,205,206,211],{},"When code is shared between files, we can make sure we don't load ",[31,201,204],{"href":202,"rel":203},"https://lodash.com/",[],"lodash"," twice, for example. If both files load lodash, we should only load the code for lodash once. Not only will lodash not be included twice, but with ",[31,207,210],{"href":208,"rel":209},"https://webpack.js.org/guides/tree-shaking/",[],"tree shaking"," only the components of lodash that we use will be included rather than the whole library.",[24,213,214,215,220],{},"We can add ",[31,216,219],{"href":217,"rel":218},"https://webpack.js.org/concepts/hot-module-replacement/",[],"hot module replacement"," to make our Vue development quicker. This is a development bonus, as our current development takes loads of time to refresh the page while developing GitLab. Spicy!",[24,222,223],{},"We can now manage our dependencies properly. This should help a lot of frontenders to contribute to GitLab. Devs won't need to figure out the whole Rails Javascript situation in order to contribute. We can also dictate manually what we want to include.",[24,225,226,227],{},"SVGs are going to be huge.\n",[111,228,229,237,240,243,246],{},[24,230,231,236],{},[31,232,235],{"href":233,"rel":234},"https://webpack.js.org/",[],"webpack"," bundles SVGs directly into our Javascript.",[24,238,239],{},"Right now, SVGs live in a specific directory in Rails. We use Rails helpers to pull in SVGs. With webpack we can pull in SVGs one at a time because webpack precompiles assets.",[24,241,242],{},"We won't have to fetch SVGs with an HTTP request.",[24,244,245],{},"We don't have to do tricky HTML hidden elements which is technical debt.",[24,247,248],{},"We don't have to mess around with SVGs in CSS. You cannot change the color of SVGs in CSS.",[24,250,251],{},"We use a lot of Ruby to solve Javascript and CSS problems. Now we can solve those problems on our own using only frontend tools.",[24,253,254,255,260],{},"Using webpack's ",[31,256,259],{"href":257,"rel":258},"https://webpack.js.org/plugins/commons-chunk-plugin/",[],"CommonsChunkPlugin"," we split all of our common vendor libraries into their own separate file. Since these change very infrequently, they can stay cached for a much longer period of time.",[24,262,263,264,269,270,192,273,276,277,280],{},"With webpack's ",[31,265,268],{"href":266,"rel":267},"https://webpack.js.org/guides/code-splitting/",[],"code splitting"," feature you can load just the JS you need to boot. Then you do a ",[154,271,272],{},"require.ensure()",[154,274,275],{},"System.import()",". With this, we can tell webpack to request only exact JS you need. It keeps the size of the file really small. For example if you have ",[154,278,279],{},"modal.js"," for modals. If someone never uses the modals the code never loads. As soon as someone opens a modal, the JS gets loaded on demand.",[24,282,283,284,287,288,291],{},"We can now properly manage our global scope. We can now do a ",[154,285,286],{},"import x from y"," instead of having our scripts pollute the global scope and pass classes around on ",[154,289,290],{},"window.gl.lol",".",[24,293,294,295,300,301,306],{},"We can slim down the our Vue bundles because we can precompile templates and omit the template compiler from our production code. ",[31,296,299],{"href":297,"rel":298},"https://twitter.com/youyuxi",[],"Evan You"," (the creator of VueJS) explains this in the ",[31,302,305],{"href":303,"rel":304},"https://github.com/vuejs/vue/issues/2873",[],"feature overview for Vue 2.0",":",[16,308,309,312],{},[12,310,311],{},"There will be two different builds:",[20,313,314,317],{},[24,315,316],{},"Standalone build: includes both the compiler and the runtime. ...",[24,318,319],{},"Runtime only build: since it doesn't include the compiler, you need to either pre-compiled templates in a compile step, or manually written render functions.",[97,321,323],{"id":322},"_3-remove-turbolinks","3. Remove Turbolinks",[12,325,326,327,332,333,338],{},"We used ",[31,328,331],{"href":329,"rel":330},"https://github.com/turbolinks/turbolinks",[],"TurboLinks"," in GitLab, but we've recently ",[31,334,337],{"href":335,"rel":336},"https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8570",[],"removed it"," with the linked merge request, merged on 2017/02/03.",[340,341,343],"h4",{"id":342},"what-does-turbolinks-achieve","What does Turbolinks achieve?",[12,345,346,347,350,351,354],{},"With TurboLinks, clicking a link won't navigate to a new page in the default browser ",[154,348,349],{},"GET"," request way. Instead, Turbolinks will replace the ",[154,352,353],{},"body"," tag of your app with the new content. All your Javascript is loaded one time, when using the asset pipeline. This usually only loads some small HTML and JavaScript. On GitLab, our pages would load an average of 20kb on each page load versus the full JavaScript file size of 800kb+. Turbolinks is a great solution for many projects. When you start introducing slightly more complex Javascript it becomes a pain.\nWe did speed tests on pages with Turbolinks and without Turbolinks and we found that the pages without Turbolinks performed better. We discovered that Turbolinks works well when you don't have a lot of event listeners to manage. To add to this, we will be able to make our pages even faster in the future because we will divide the Javascript up between pages better with the help of webpack. We were previously writing a lot of extra code to handle all of Turbolink's problems and we can remove that code now.",[340,356,358],{"id":357},"the-problem-we-need-to-solve","The problem we need to solve",[12,360,361,362,365,366,369,370,373],{},"When your JS is loaded one time for multiple pages, events become a major problem. If you are using ",[154,363,364],{},"gem 'jquery-turbolinks'"," as we are, then the ",[154,367,368],{},"$"," ",[154,371,372],{},"ready"," function will fire on every page load even though the page isn't loading in the traditional sense. It's painful to write page specific Javascript without including it for the whole app. We do it and it's fine, but, why? There really isn't a reason for a lot of our JS that needs to be included on every page.",[12,375,376],{},"Any external links do load faster so, we need to be careful about performance.",[12,378,379],{},"If you aren't careful, your events will get loaded multiple times and thus fire multiple times. For example, take the following code:",[381,382,387],"pre",{"className":383,"code":384,"language":385,"meta":386,"style":386},"language-js shiki shiki-themes github-light","$(function(){\n  $(document).on('click','.some-element', function(){\n    console.log('Click loaded');\n  }\n});\n","js","",[154,388,389,408,439,456,462],{"__ignoreMap":386},[390,391,394,397,401,405],"span",{"class":392,"line":393},"line",1,[390,395,368],{"class":396},"s7eDp",[390,398,400],{"class":399},"sgsFI","(",[390,402,404],{"class":403},"sD7c4","function",[390,406,407],{"class":399},"(){\n",[390,409,411,414,417,420,422,426,429,432,435,437],{"class":392,"line":410},2,[390,412,413],{"class":396},"  $",[390,415,416],{"class":399},"(document).",[390,418,419],{"class":396},"on",[390,421,400],{"class":399},[390,423,425],{"class":424},"sYBdl","'click'",[390,427,428],{"class":399},",",[390,430,431],{"class":424},"'.some-element'",[390,433,434],{"class":399},", ",[390,436,404],{"class":403},[390,438,407],{"class":399},[390,440,442,445,448,450,453],{"class":392,"line":441},3,[390,443,444],{"class":399},"    console.",[390,446,447],{"class":396},"log",[390,449,400],{"class":399},[390,451,452],{"class":424},"'Click loaded'",[390,454,455],{"class":399},");\n",[390,457,459],{"class":392,"line":458},4,[390,460,461],{"class":399},"  }\n",[390,463,465],{"class":392,"line":464},5,[390,466,467],{"class":399},"});\n",[12,469,470,471,474],{},"That click event will be loaded on every page and thus fire multiple times every time ",[154,472,473],{},".some-element"," is clicked.",[340,476,478],{"id":477},"the-solutions","The Solutions",[12,480,481],{},"There are a few remedies to this problem. Some are good and some are bad.",[111,483,484,492,553,556],{},[24,485,486,487,369,489,491],{},"Don't create events in ",[154,488,368],{},[154,490,372],{}," callbacks.",[24,493,494,495,538,541,542,545,546,549,550,291],{},"Use the following stinky solution:",[381,496,498],{"className":383,"code":497,"language":385,"meta":386,"style":386},"$(document)\n.off('click', '.some-element')\n.on('click'...\n",[154,499,500,507,525],{"__ignoreMap":386},[390,501,502,504],{"class":392,"line":393},[390,503,368],{"class":396},[390,505,506],{"class":399},"(document)\n",[390,508,509,511,514,516,518,520,522],{"class":392,"line":410},[390,510,291],{"class":399},[390,512,513],{"class":396},"off",[390,515,400],{"class":399},[390,517,425],{"class":424},[390,519,434],{"class":399},[390,521,431],{"class":424},[390,523,524],{"class":399},")\n",[390,526,527,529,531,533,535],{"class":392,"line":441},[390,528,291],{"class":399},[390,530,419],{"class":396},[390,532,400],{"class":399},[390,534,425],{"class":424},[390,536,537],{"class":403},"...\n",[539,540],"br",{},"I call this the ",[154,543,544],{},"die live"," method. Old jQuery code people use to write ",[154,547,548],{},"die().live()"," everywhere. That's the old school jQuery ",[154,551,552],{},"off().on()",[24,554,555],{},"Write an event manager to be a delegate for all added events.",[24,557,558,562],{},[31,559,561],{"href":335,"rel":560},[],"Remove Turbolinks"," and make sure you load only the code you need on each page.",[12,564,565],{},"I am opting for option 4, in order to make our development lives easier and get multiple performance gains.",[340,567,569],{"id":568},"the-bonus","The Bonus",[12,571,572],{},"After we remove Turbolinks we can do something really cool. We can have each page live on its own. Then, certain pages can be their own Vue apps. For example, we can make the file browser its own Vue application. The merge request page can be its own application. The code for the file viewer won't need to be loaded on any other page and the same goes for other pages. This is not anything new, this is just basic web development. This is also not a new paradigm, and we would not be the first.",[53,574,576],{"id":575},"conclusion","Conclusion",[12,578,579],{},"There is the argument for making the whole site a single page application, but I think this would just be the hardest to maintain and has zero benefits for the performance and the user. Also, there's a higher chance of making GitLab a janky app. For example, the profile page could be potentially very light, and there would be no reason for that if someone is linked directly to the profile page; it should load every single piece of Javascript in our project.",[12,581,582],{},"This is just one small step for GitLab and one giant leap for the frontend team. In the future you will see many new cool things coming from our team. This move was one step in that direction.",[12,584,585,586,591],{},"Questions, suggestions, ideas? Please leave a comment\nbelow or tweet at us ",[31,587,590],{"href":588,"rel":589},"https://twitter.com/gitlab",[],"@GitLab","!",[593,594,595],"style",{},"html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":386,"searchDepth":410,"depth":410,"links":597},[598,599,604],{"id":55,"depth":410,"text":56},{"id":91,"depth":410,"text":92,"children":600},[601,602,603],{"id":99,"depth":441,"text":100},{"id":148,"depth":441,"text":149},{"id":322,"depth":441,"text":323},{"id":575,"depth":410,"text":576},"engineering","2017-02-06","Our long term plan to make GitLab as fast and performant as possible with Vue and webpack.","md",null,false,"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749683983/Blog/Hero%20Images/vue-big-plan-cover.png",{"excerpt":613},{"type":9,"value":614},[615],[12,616,14],{},true,"/en-us/blog/vue-big-plan",{"title":5,"description":607,"ogTitle":5,"ogDescription":607,"noIndex":610,"ogImage":611,"ogUrl":620,"ogSiteName":621,"ogType":622,"canonicalUrls":620},"https://about.gitlab.com/blog/vue-big-plan","https://about.gitlab.com","article","vue-big-plan","en-us/blog/vue-big-plan","BlogPost","LwaDiP74JLvzuDuSvnSvYf7YngH9xglAFH2p4C02i20",{"logo":628,"freeTrial":633,"sales":638,"login":643,"items":648,"search":974,"minimal":1005,"duo":1024,"switchNav":1033,"pricingDeployment":1044},{"config":629},{"href":630,"dataGaName":631,"dataGaLocation":632},"/","gitlab logo","header",{"text":634,"config":635},"Get free trial",{"href":636,"dataGaName":637,"dataGaLocation":632},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com&glm_content=default-saas-trial/","free trial",{"text":639,"config":640},"Request a demo",{"href":641,"dataGaName":642,"dataGaLocation":632},"/sales/?contact-topic=request-demo","sales",{"text":644,"config":645},"Sign in",{"href":646,"dataGaName":647,"dataGaLocation":632},"https://gitlab.com/users/sign_in/","sign in",[649,678,777,782,896,952],{"text":650,"config":651,"menu":653},"Platform",{"dataNavLevelOne":652},"platform",{"type":654,"columns":655},"cards",[656,662,670],{"title":650,"description":657,"link":658},"The intelligent orchestration platform for DevSecOps",{"text":659,"config":660},"Explore our Platform",{"href":661,"dataGaName":652,"dataGaLocation":632},"/platform/",{"title":663,"description":664,"link":665},"GitLab Duo Agent Platform","Agentic AI for the entire software lifecycle",{"text":666,"config":667},"Meet GitLab Duo",{"href":668,"dataGaName":669,"dataGaLocation":632},"/gitlab-duo-agent-platform/","gitlab duo agent platform",{"title":671,"description":672,"link":673},"Why GitLab","See the top reasons enterprises choose GitLab",{"text":674,"config":675},"Learn more",{"href":676,"dataGaName":677,"dataGaLocation":632},"/why-gitlab/","why gitlab",{"text":679,"left":617,"config":680,"menu":682},"Product",{"dataNavLevelOne":681},"solutions",{"type":683,"link":684,"columns":688,"feature":756},"lists",{"text":685,"config":686},"View all Solutions",{"href":687,"dataGaName":681,"dataGaLocation":632},"/solutions/",[689,712,735],{"title":690,"description":691,"link":692,"items":697},"Automation","CI/CD and automation to accelerate deployment",{"config":693},{"icon":694,"href":695,"dataGaName":696,"dataGaLocation":632},"AutomatedCodeAlt","/solutions/delivery-automation/","automated software delivery",[698,702,705,708],{"text":699,"config":700},"CI/CD",{"href":701,"dataGaLocation":632,"dataGaName":699},"/solutions/continuous-integration/",{"text":663,"config":703},{"href":668,"dataGaLocation":632,"dataGaName":704},"gitlab duo agent platform - product menu",{"text":706,"config":707},"Source Code Management",{"href":186,"dataGaLocation":632,"dataGaName":706},{"text":709,"config":710},"Automated Software Delivery",{"href":695,"dataGaLocation":632,"dataGaName":711},"Automated software delivery",{"title":713,"description":714,"link":715,"items":720},"Security","Deliver code faster without compromising security",{"config":716},{"href":717,"dataGaName":718,"dataGaLocation":632,"icon":719},"/solutions/application-security-testing/","security and compliance","ShieldCheckLight",[721,725,730],{"text":722,"config":723},"Application Security Testing",{"href":717,"dataGaName":724,"dataGaLocation":632},"Application security testing",{"text":726,"config":727},"Software Supply Chain Security",{"href":728,"dataGaLocation":632,"dataGaName":729},"/solutions/supply-chain/","Software supply chain security",{"text":731,"config":732},"Software Compliance",{"href":733,"dataGaName":734,"dataGaLocation":632},"/solutions/software-compliance/","software compliance",{"title":736,"link":737,"items":742},"Measurement",{"config":738},{"icon":739,"href":740,"dataGaName":741,"dataGaLocation":632},"DigitalTransformation","/solutions/visibility-measurement/","visibility and measurement",[743,747,751],{"text":744,"config":745},"Visibility & Measurement",{"href":740,"dataGaLocation":632,"dataGaName":746},"Visibility and Measurement",{"text":748,"config":749},"Value Stream Management",{"href":750,"dataGaLocation":632,"dataGaName":748},"/solutions/value-stream-management/",{"text":752,"config":753},"Analytics & Insights",{"href":754,"dataGaLocation":632,"dataGaName":755},"/solutions/analytics-and-insights/","Analytics and insights",{"title":757,"type":683,"items":758},"GitLab for",[759,765,771],{"text":760,"config":761},"Enterprise",{"icon":762,"href":763,"dataGaLocation":632,"dataGaName":764},"Building","/enterprise/","enterprise",{"text":766,"config":767},"Small Business",{"icon":768,"href":769,"dataGaLocation":632,"dataGaName":770},"Work","/small-business/","small business",{"text":772,"config":773},"Public Sector",{"icon":774,"href":775,"dataGaLocation":632,"dataGaName":776},"Organization","/solutions/public-sector/","public sector",{"text":778,"config":779},"Pricing",{"href":780,"dataGaName":781,"dataGaLocation":632,"dataNavLevelOne":781},"/pricing/","pricing",{"text":783,"config":784,"menu":786},"Resources",{"dataNavLevelOne":785},"resources",{"type":683,"link":787,"columns":791,"feature":885},{"text":788,"config":789},"View all resources",{"href":790,"dataGaName":785,"dataGaLocation":632},"/resources/",[792,825,852],{"title":793,"items":794},"Getting started",[795,800,805,810,815,820],{"text":796,"config":797},"Install",{"href":798,"dataGaName":799,"dataGaLocation":632},"/install/","install",{"text":801,"config":802},"Quick start guides",{"href":803,"dataGaName":804,"dataGaLocation":632},"/get-started/","quick setup checklists",{"text":806,"config":807},"Learn",{"href":808,"dataGaLocation":632,"dataGaName":809},"https://university.gitlab.com/","learn",{"text":811,"config":812},"Product documentation",{"href":813,"dataGaName":814,"dataGaLocation":632},"https://docs.gitlab.com/","product documentation",{"text":816,"config":817},"Best practice videos",{"href":818,"dataGaName":819,"dataGaLocation":632},"/getting-started-videos/","best practice videos",{"text":821,"config":822},"Integrations",{"href":823,"dataGaName":824,"dataGaLocation":632},"/integrations/","integrations",{"title":826,"items":827},"Discover",[828,833,838,843,847],{"text":829,"config":830},"Customer success stories",{"href":831,"dataGaName":832,"dataGaLocation":632},"/customers/","customer success stories",{"text":834,"config":835},"Blog",{"href":836,"dataGaName":837,"dataGaLocation":632},"/blog/","blog",{"text":839,"config":840},"Demo Hub",{"href":841,"dataGaName":842,"dataGaLocation":632},"/demo-hub/","demo hub",{"text":844,"config":845},"The Source",{"href":846,"dataGaName":837,"dataGaLocation":632},"/the-source/",{"text":848,"config":849},"Remote",{"href":850,"dataGaName":851,"dataGaLocation":632},"https://handbook.gitlab.com/handbook/company/culture/all-remote/","remote",{"title":853,"items":854},"Connect",[855,860,865,870,875,880],{"text":856,"config":857},"GitLab Services",{"href":858,"dataGaName":859,"dataGaLocation":632},"/services/","services",{"text":861,"config":862},"Contribute",{"href":863,"dataGaName":864,"dataGaLocation":632},"https://contributors.gitlab.com","contribute",{"text":866,"config":867},"Community",{"href":868,"dataGaName":869,"dataGaLocation":632},"/community/","community",{"text":871,"config":872},"Forum",{"href":873,"dataGaName":874,"dataGaLocation":632},"https://forum.gitlab.com/","forum",{"text":876,"config":877},"Events",{"href":878,"dataGaName":879,"dataGaLocation":632},"/events/","events",{"text":881,"config":882},"Partners",{"href":883,"dataGaName":884,"dataGaLocation":632},"/partners/","partners",{"config":886,"title":889,"text":890,"link":891},{"background":887,"textColor":888},"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":892,"config":893},"Read the latest",{"href":894,"dataGaName":895,"dataGaLocation":632},"/whats-new/","whats new",{"text":897,"config":898,"menu":900},"Company",{"dataNavLevelOne":899},"company",{"type":683,"columns":901},[902],{"items":903},[904,909,915,917,922,927,932,937,942,947],{"text":905,"config":906},"About",{"href":907,"dataGaName":908,"dataGaLocation":632},"/company/","about",{"text":910,"config":911,"footerGa":914},"Jobs",{"href":912,"dataGaName":913,"dataGaLocation":632},"/jobs/","jobs",{"dataGaName":913},{"text":876,"config":916},{"href":878,"dataGaName":879,"dataGaLocation":632},{"text":918,"config":919},"Leadership",{"href":920,"dataGaName":921,"dataGaLocation":632},"/company/team/e-group/","leadership",{"text":923,"config":924},"Handbook",{"href":925,"dataGaName":926,"dataGaLocation":632},"https://handbook.gitlab.com/","handbook",{"text":928,"config":929},"Investor relations",{"href":930,"dataGaName":931,"dataGaLocation":632},"https://ir.gitlab.com/overview/default.aspx","investor relations",{"text":933,"config":934},"Trust Center",{"href":935,"dataGaName":936,"dataGaLocation":632},"/security/","trust center",{"text":938,"config":939},"AI Transparency Center",{"href":940,"dataGaName":941,"dataGaLocation":632},"/ai-transparency-center/","ai transparency center",{"text":943,"config":944},"Newsletter",{"href":945,"dataGaName":946,"dataGaLocation":632},"/company/contact/#contact-forms","newsletter",{"text":948,"config":949},"Press",{"href":950,"dataGaName":951,"dataGaLocation":632},"/press/","press",{"text":953,"config":954,"menu":955},"Contact us",{"dataNavLevelOne":899},{"type":683,"columns":956},[957],{"items":958},[959,964,969],{"text":960,"config":961},"Talk to sales",{"href":962,"dataGaName":963,"dataGaLocation":632},"/sales/","talk to sales",{"text":965,"config":966},"Support portal",{"href":967,"dataGaName":968,"dataGaLocation":632},"https://support.gitlab.com/hc/en-us","support portal",{"text":970,"config":971},"Customer portal",{"href":972,"dataGaName":973,"dataGaLocation":632},"https://customers.gitlab.com/customers/sign_in/","customer portal",{"close":975,"login":976,"suggestions":983},"Close",{"text":977,"link":978},"To search repositories and projects, login to",{"text":979,"config":980},"gitlab.com",{"href":646,"dataGaName":981,"dataGaLocation":982},"search login","search",{"text":984,"default":985},"Suggestions",[986,988,992,994,998,1002],{"text":663,"config":987},{"href":668,"dataGaName":663,"dataGaLocation":982},{"text":989,"config":990},"Code Suggestions (AI)",{"href":991,"dataGaName":989,"dataGaLocation":982},"/solutions/code-suggestions/",{"text":699,"config":993},{"href":701,"dataGaName":699,"dataGaLocation":982},{"text":995,"config":996},"GitLab on AWS",{"href":997,"dataGaName":995,"dataGaLocation":982},"/partners/technology-partners/aws/",{"text":999,"config":1000},"GitLab on Google Cloud",{"href":1001,"dataGaName":999,"dataGaLocation":982},"/partners/technology-partners/google-cloud-platform/",{"text":1003,"config":1004},"Why GitLab?",{"href":676,"dataGaName":1003,"dataGaLocation":982},{"freeTrial":1006,"mobileIcon":1011,"desktopIcon":1016,"secondaryButton":1019},{"text":1007,"config":1008},"Start free trial",{"href":1009,"dataGaName":637,"dataGaLocation":1010},"https://gitlab.com/-/trials/new/","nav",{"altText":1012,"config":1013},"Gitlab Icon",{"src":1014,"dataGaName":1015,"dataGaLocation":1010},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203874/jypbw1jx72aexsoohd7x.svg","gitlab icon",{"altText":1012,"config":1017},{"src":1018,"dataGaName":1015,"dataGaLocation":1010},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203875/gs4c8p8opsgvflgkswz9.svg",{"text":1020,"config":1021},"Get Started",{"href":1022,"dataGaName":1023,"dataGaLocation":1010},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com/get-started/","get started",{"freeTrial":1025,"mobileIcon":1029,"desktopIcon":1031},{"text":1026,"config":1027},"Learn more about GitLab Duo",{"href":668,"dataGaName":1028,"dataGaLocation":1010},"gitlab duo",{"altText":1012,"config":1030},{"src":1014,"dataGaName":1015,"dataGaLocation":1010},{"altText":1012,"config":1032},{"src":1018,"dataGaName":1015,"dataGaLocation":1010},{"button":1034,"mobileIcon":1039,"desktopIcon":1041},{"text":1035,"config":1036},"/switch",{"href":1037,"dataGaName":1038,"dataGaLocation":1010},"#contact","switch",{"altText":1012,"config":1040},{"src":1014,"dataGaName":1015,"dataGaLocation":1010},{"altText":1012,"config":1042},{"src":1043,"dataGaName":1015,"dataGaLocation":1010},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1773335277/ohhpiuoxoldryzrnhfrh.png",{"freeTrial":1045,"mobileIcon":1050,"desktopIcon":1052},{"text":1046,"config":1047},"Back to pricing",{"href":780,"dataGaName":1048,"dataGaLocation":1010,"icon":1049},"back to pricing","GoBack",{"altText":1012,"config":1051},{"src":1014,"dataGaName":1015,"dataGaLocation":1010},{"altText":1012,"config":1053},{"src":1018,"dataGaName":1015,"dataGaLocation":1010},{"title":1055,"titleMobile":1056,"button":1057,"config":1062},"Duo Agent Platform delivers 400% ROI, per new Forrester Consulting study.","400% ROI: Forrester TEI for GitLab Duo",{"text":674,"config":1058},{"href":1059,"dataGaName":1060,"dataGaLocation":1061},"https://about.gitlab.com/blog/gitlab-duo-agent-platform-delivers-400-percent-roi/","forrester-tei-dap-banner","global-banner",{"layout":1063,"disabled":610},"release",{"data":1065},{"text":1066,"source":1067,"edit":1073,"contribute":1078,"config":1083,"items":1087,"minimal":1297},"Git is a trademark of Software Freedom Conservancy and our use of 'GitLab' is under license",{"text":1068,"config":1069},"View page source",{"href":1070,"dataGaName":1071,"dataGaLocation":1072},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/","page source","footer",{"text":1074,"config":1075},"Edit this page",{"href":1076,"dataGaName":1077,"dataGaLocation":1072},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/content/","web ide",{"text":1079,"config":1080},"Please contribute",{"href":1081,"dataGaName":1082,"dataGaLocation":1072},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/CONTRIBUTING.md/","please contribute",{"twitter":588,"facebook":1084,"youtube":1085,"linkedin":1086},"https://www.facebook.com/gitlab","https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg","https://www.linkedin.com/company/gitlab-com",[1088,1135,1189,1233,1265],{"title":778,"links":1089,"subMenu":1104},[1090,1094,1099],{"text":1091,"config":1092},"View plans",{"href":780,"dataGaName":1093,"dataGaLocation":1072},"view plans",{"text":1095,"config":1096},"Why Premium?",{"href":1097,"dataGaName":1098,"dataGaLocation":1072},"/pricing/premium/","why premium",{"text":1100,"config":1101},"Why Ultimate?",{"href":1102,"dataGaName":1103,"dataGaLocation":1072},"/pricing/ultimate/","why ultimate",[1105],{"title":1106,"links":1107},"Contact Us",[1108,1111,1113,1115,1120,1125,1130],{"text":1109,"config":1110},"Contact sales",{"href":962,"dataGaName":642,"dataGaLocation":1072},{"text":965,"config":1112},{"href":967,"dataGaName":968,"dataGaLocation":1072},{"text":970,"config":1114},{"href":972,"dataGaName":973,"dataGaLocation":1072},{"text":1116,"config":1117},"Status",{"href":1118,"dataGaName":1119,"dataGaLocation":1072},"https://status.gitlab.com/","status",{"text":1121,"config":1122},"Terms of use",{"href":1123,"dataGaName":1124,"dataGaLocation":1072},"/terms/","terms of use",{"text":1126,"config":1127},"Privacy statement",{"href":1128,"dataGaName":1129,"dataGaLocation":1072},"/privacy/","privacy statement",{"text":1131,"config":1132},"Cookie preferences",{"dataGaName":1133,"dataGaLocation":1072,"id":1134,"isOneTrustButton":617},"cookie preferences","ot-sdk-btn",{"title":679,"links":1136,"subMenu":1145},[1137,1141],{"text":1138,"config":1139},"DevSecOps platform",{"href":661,"dataGaName":1140,"dataGaLocation":1072},"devsecops platform",{"text":1142,"config":1143},"AI-Assisted Development",{"href":668,"dataGaName":1144,"dataGaLocation":1072},"ai-assisted development",[1146],{"title":1147,"links":1148},"Topics",[1149,1154,1159,1164,1169,1174,1179,1184],{"text":1150,"config":1151},"CICD",{"href":1152,"dataGaName":1153,"dataGaLocation":1072},"/topics/ci-cd/","cicd",{"text":1155,"config":1156},"GitOps",{"href":1157,"dataGaName":1158,"dataGaLocation":1072},"/topics/gitops/","gitops",{"text":1160,"config":1161},"DevOps",{"href":1162,"dataGaName":1163,"dataGaLocation":1072},"/topics/devops/","devops",{"text":1165,"config":1166},"Version Control",{"href":1167,"dataGaName":1168,"dataGaLocation":1072},"/topics/version-control/","version control",{"text":1170,"config":1171},"DevSecOps",{"href":1172,"dataGaName":1173,"dataGaLocation":1072},"/topics/devsecops/","devsecops",{"text":1175,"config":1176},"Cloud Native",{"href":1177,"dataGaName":1178,"dataGaLocation":1072},"/topics/cloud-native/","cloud native",{"text":1180,"config":1181},"AI for Coding",{"href":1182,"dataGaName":1183,"dataGaLocation":1072},"/topics/devops/ai-for-coding/","ai for coding",{"text":1185,"config":1186},"Agentic AI",{"href":1187,"dataGaName":1188,"dataGaLocation":1072},"/topics/agentic-ai/","agentic ai",{"title":1190,"links":1191},"Solutions",[1192,1194,1196,1201,1205,1208,1212,1215,1217,1220,1223,1228],{"text":722,"config":1193},{"href":717,"dataGaName":722,"dataGaLocation":1072},{"text":711,"config":1195},{"href":695,"dataGaName":696,"dataGaLocation":1072},{"text":1197,"config":1198},"Agile development",{"href":1199,"dataGaName":1200,"dataGaLocation":1072},"/solutions/agile-delivery/","agile delivery",{"text":1202,"config":1203},"SCM",{"href":186,"dataGaName":1204,"dataGaLocation":1072},"source code management",{"text":1150,"config":1206},{"href":701,"dataGaName":1207,"dataGaLocation":1072},"continuous integration & delivery",{"text":1209,"config":1210},"Value stream management",{"href":750,"dataGaName":1211,"dataGaLocation":1072},"value stream management",{"text":1155,"config":1213},{"href":1214,"dataGaName":1158,"dataGaLocation":1072},"/solutions/gitops/",{"text":760,"config":1216},{"href":763,"dataGaName":764,"dataGaLocation":1072},{"text":1218,"config":1219},"Small business",{"href":769,"dataGaName":770,"dataGaLocation":1072},{"text":1221,"config":1222},"Public sector",{"href":775,"dataGaName":776,"dataGaLocation":1072},{"text":1224,"config":1225},"Education",{"href":1226,"dataGaName":1227,"dataGaLocation":1072},"/solutions/education/","education",{"text":1229,"config":1230},"Financial services",{"href":1231,"dataGaName":1232,"dataGaLocation":1072},"/solutions/finance/","financial services",{"title":783,"links":1234},[1235,1237,1239,1241,1244,1246,1249,1251,1253,1255,1257,1259,1261,1263],{"text":796,"config":1236},{"href":798,"dataGaName":799,"dataGaLocation":1072},{"text":801,"config":1238},{"href":803,"dataGaName":804,"dataGaLocation":1072},{"text":806,"config":1240},{"href":808,"dataGaName":809,"dataGaLocation":1072},{"text":811,"config":1242},{"href":813,"dataGaName":1243,"dataGaLocation":1072},"docs",{"text":834,"config":1245},{"href":836,"dataGaName":837,"dataGaLocation":1072},{"text":1247,"config":1248},"What's new",{"href":894,"dataGaName":895,"dataGaLocation":1072},{"text":829,"config":1250},{"href":831,"dataGaName":832,"dataGaLocation":1072},{"text":848,"config":1252},{"href":850,"dataGaName":851,"dataGaLocation":1072},{"text":856,"config":1254},{"href":858,"dataGaName":859,"dataGaLocation":1072},{"text":861,"config":1256},{"href":863,"dataGaName":864,"dataGaLocation":1072},{"text":866,"config":1258},{"href":868,"dataGaName":869,"dataGaLocation":1072},{"text":871,"config":1260},{"href":873,"dataGaName":874,"dataGaLocation":1072},{"text":876,"config":1262},{"href":878,"dataGaName":879,"dataGaLocation":1072},{"text":881,"config":1264},{"href":883,"dataGaName":884,"dataGaLocation":1072},{"title":897,"links":1266},[1267,1269,1271,1273,1275,1277,1281,1286,1288,1290,1292],{"text":905,"config":1268},{"href":907,"dataGaName":899,"dataGaLocation":1072},{"text":910,"config":1270},{"href":912,"dataGaName":913,"dataGaLocation":1072},{"text":918,"config":1272},{"href":920,"dataGaName":921,"dataGaLocation":1072},{"text":923,"config":1274},{"href":925,"dataGaName":926,"dataGaLocation":1072},{"text":928,"config":1276},{"href":930,"dataGaName":931,"dataGaLocation":1072},{"text":1278,"config":1279},"Sustainability",{"href":1280,"dataGaName":1278,"dataGaLocation":1072},"/sustainability/",{"text":1282,"config":1283},"Diversity, inclusion and belonging (DIB)",{"href":1284,"dataGaName":1285,"dataGaLocation":1072},"/diversity-inclusion-belonging/","Diversity, inclusion and belonging",{"text":933,"config":1287},{"href":935,"dataGaName":936,"dataGaLocation":1072},{"text":943,"config":1289},{"href":945,"dataGaName":946,"dataGaLocation":1072},{"text":948,"config":1291},{"href":950,"dataGaName":951,"dataGaLocation":1072},{"text":1293,"config":1294},"Modern Slavery Transparency Statement",{"href":1295,"dataGaName":1296,"dataGaLocation":1072},"https://handbook.gitlab.com/handbook/legal/modern-slavery-act-transparency-statement/","modern slavery transparency statement",{"items":1298},[1299,1302,1305],{"text":1300,"config":1301},"Terms",{"href":1123,"dataGaName":1124,"dataGaLocation":1072},{"text":1303,"config":1304},"Cookies",{"dataGaName":1133,"dataGaLocation":1072,"id":1134,"isOneTrustButton":617},{"text":1306,"config":1307},"Privacy",{"href":1128,"dataGaName":1129,"dataGaLocation":1072},[1309],{"id":1310,"title":7,"body":609,"config":1311,"content":1313,"description":609,"extension":1316,"meta":1317,"navigation":617,"path":1318,"seo":1319,"stem":1320,"__hash__":1321},"blogAuthors/en-us/blog/authors/jacob-schatz.yml",{"template":1312},"BlogAuthor",{"name":7,"config":1314},{"headshot":386,"ctfId":1315},"jschatz1","yml",{},"/en-us/blog/authors/jacob-schatz",{},"en-us/blog/authors/jacob-schatz","5Ni1pJap-3Oy_IR41XlYvyewBFNZN8dZyOWznuyUvoM",[1323,1332,1340],{"title":1324,"description":1325,"heroImage":1326,"category":605,"date":1327,"authors":1328,"slug":1331,"externalUrl":609},"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",[1329,1330],"Mathias Ewald","Martin Paloncy, Edgeless Systems","confidential-ai-for-gitlab-self-hosted",{"title":1333,"description":1334,"heroImage":1335,"category":605,"date":1336,"authors":1337,"slug":1339,"externalUrl":609},"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",[1338],"Lysanne Pinto","green-devops-carbon-measurement-cicd-pipeline",{"title":1341,"description":1342,"heroImage":1343,"category":605,"date":1344,"authors":1345,"slug":1347,"externalUrl":609},"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",[1346],"Paul Meresanu","how-to-build-ci-cd-observability-at-scale",{"promotions":1349},[1350,1364,1376,1388],{"id":1351,"categories":1352,"header":1354,"text":1355,"button":1356,"image":1361},"ai-modernization",[1353],"ai","Is AI achieving its promise at scale?","Quiz will take 5 minutes or less",{"text":1357,"config":1358},"Get your AI maturity score",{"href":1359,"dataGaName":1360,"dataGaLocation":837},"/assessments/ai-modernization-assessment/","modernization assessment",{"config":1362},{"src":1363},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/qix0m7kwnd8x2fh1zq49.png",{"id":1365,"categories":1366,"header":1368,"text":1355,"button":1369,"image":1373},"devops-modernization",[1367,1173],"product","Are you just managing tools or shipping innovation?",{"text":1370,"config":1371},"Get your DevOps maturity score",{"href":1372,"dataGaName":1360,"dataGaLocation":837},"/assessments/devops-modernization-assessment/",{"config":1374},{"src":1375},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138785/eg818fmakweyuznttgid.png",{"id":1377,"categories":1378,"header":1380,"text":1355,"button":1381,"image":1385},"security-modernization",[1379],"security","Are you trading speed for security?",{"text":1382,"config":1383},"Get your security maturity score",{"href":1384,"dataGaName":1360,"dataGaLocation":837},"/assessments/security-modernization-assessment/",{"config":1386},{"src":1387},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/p4pbqd9nnjejg5ds6mdk.png",{"id":1389,"paths":1390,"header":1393,"text":1394,"button":1395,"image":1400},"github-azure-migration",[1391,1392],"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":1396,"config":1397},"See how GitLab compares to GitHub",{"href":1398,"dataGaName":1399,"dataGaLocation":837},"/compare/gitlab-vs-github/github-azure-migration/","github azure migration",{"config":1401},{"src":1375},{"header":1403,"blurb":1404,"button":1405,"secondaryButton":1410},"Start building faster today","See what your team can do with the intelligent orchestration platform for DevSecOps.\n",{"text":1406,"config":1407},"Get your free trial",{"href":1408,"dataGaName":637,"dataGaLocation":1409},"https://gitlab.com/-/trial_registrations/new?glm_content=default-saas-trial&glm_source=about.gitlab.com/","feature",{"text":1109,"config":1411},{"href":962,"dataGaName":642,"dataGaLocation":1409},1786803738993]