[{"data":1,"prerenderedAt":718},["ShallowReactive",2],{"/en-us/blog/gitlab-vue-one-year-later/":3,"navigation-en-us":35,"banner-en-us":464,"footer-en-us":481,"Jacob Schatz":691,"next-steps-en-us":703},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"seo":8,"content":16,"config":25,"_id":28,"_type":29,"title":30,"_source":31,"_file":32,"_stem":33,"_extension":34},"/en-us/blog/gitlab-vue-one-year-later","blog",false,"",{"title":9,"description":10,"ogTitle":9,"ogDescription":10,"noIndex":6,"ogImage":11,"ogUrl":12,"ogSiteName":13,"ogType":14,"canonicalUrls":12,"schema":15},"How we do Vue: one year later","How we, at GitLab, write VueJS, one year later.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749680321/Blog/Hero%20Images/vue-title.jpg","https://about.gitlab.com/blog/gitlab-vue-one-year-later","https://about.gitlab.com","article","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How we do Vue: one year later\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Jacob Schatz\"}],\n        \"datePublished\": \"2017-11-09\",\n      }",{"title":9,"description":10,"authors":17,"heroImage":11,"date":19,"body":20,"category":21,"tags":22},[18],"Jacob Schatz","2017-11-09","It's been a while since [we wrote about Vue](/blog/why-we-chose-vue/). We've\nbeen using Vue for over a year now and life has been very good. Thanks\n[@lnoogn](https://twitter.com/lnoogn) for reminding me to write this\narticle!\n\n\n\u003C!-- more -->\n\n\nOur situation reminds me of a quote about Scala from [\"Is Scala slowly\ndying?\"](https://www.reddit.com/r/scala/comments/2hw0bp/is_scala_slowly_dying/)\nSomeone once said:\n\n\n> Scala people don't have time for redditing and blogging, they're busy\ngetting crap done.\n\n\nWhich is exactly what we've been doing. Like Scala, Vue works really, really\nwell, when used properly. It turns out Vue isn't a buzzword, Vue is a\nworkhorse. A lot of our problems have been solved, by us and others. We\nstill have problems but, we now have a reproducible \"way to write Vue.\" We\ndon't adopt every new idea out there, but we have changed a few things since\nwe last spoke.\n\n\nSince that last post, we published a [very extensive Vue style\nguide](https://docs.gitlab.com/ee/development/fe_guide/vue.html), after\nwhich Vue also put out a [style guide](https://vuejs.org/v2/style-guide/),\n[taking inspiration from\nours](https://github.com/vuejs/eslint-plugin-vue/issues/77#issuecomment-315834845).\nThe style guide has been updated several times as we discover better ways to\nwrite Vue. Here are some of the things we discovered.\n\n\n## Just use VueX\n\n\nWe discovered that [VueX](https://vuex.vuejs.org/) makes our lives easier.\nIf you are writing a medium to large feature, use VueX. If it's a tiny\nfeature, you might get away without it. We made the mistake of not using\nVueX for a large feature. We wrote a [multi-file\neditor](https://gitlab.com/gitlab-org/gitlab-ce/issues/31890) (WIP) to\nreplace our current repo file view, to allow easy editing of multiple files.\n\n\n![multi-file-editor.png](https://about.gitlab.com/images/vue_2017/multi-file-editor.png){:\n.shadow}\n\n\nIn the beginning we did not use VueX for this feature and instead used the\nstore pattern. The Vue docs talk about the [store\npattern](https://vuejs.org/v2/guide/state-management.html#Simple-State-Management-from-Scratch),\nwhich works well when you are committed to strictly keeping to the pattern.\nWe've found that you are better off spending your time with VueX instead.\nWhile VueX is initially more verbose, it is much more scalable, and will\nsave you tons of time in the long run. Our mistake happened when we changed\nthe data in multiple places. In VueX you are forced to change the data in\none central place. If you don't do this, you will wind up chasing unexpected\nbugs around.\n\n\n## Write high quality code\n\n\nEven though VueJS and VueX are both wonderful, it is still possible (as with\nany code) to write bad Vue code. While the code may work, your longevity and\nscalability may suffer. Performance can suffer. With Vue, it makes it so\neasy to have what seems like working, perfect code because Vue is so simple\nto write. Longevity problems can mean that your code initially works, but\nyou (and others) will have a hard time trying to update the code.\nPerformance problems might not crop up with small data sets, but will with\nlarger ones. Code can get messy. Your code can get smelly. Yes, even with\nVue, you can have [code smell](https://en.wikipedia.org/wiki/Code_smell).\n\n\nWhen you add something to the `data` object or the `store` for Vue to keep\ntrack of, Vue will recursively walk down your data object and keep track of\neverything. If your data is super hierarchical and just large in general,\nand you are changing things often (like maybe on `mousemove`), then you can\ncreate jank. It's not bad to have Vue observe large data sets, but just\nconfirm that you do in fact need the data you are watching to be reactive.\nIt's easy with Vue to just make everything reactive, when it might not need\nto be.\n\n\nThat's why we are very strict when anyone writes Vue code. They must [follow\nour\ndocumentation](https://docs.gitlab.com/ee/development/fe_guide/vue.html).\nThey must also only write Vue when it is necessary and not write it [when it\nis\noverkill](https://docs.gitlab.com/ee/development/fe_guide/vue.html#when-not-to-use-vue-js).\n\n\nAll of our new Vue code follows the [Flux\narchitecture](https://facebook.github.io/flux/). VueX also follows Flux,\nwhich is part of the reason we use VueX. You can use the previously\nmentioned \"store pattern,\" but VueX is a better choice because it enforces\nall of the rules. If you go rogue, you will wind up enforcing the rules\nyourself, and you will probably make mistakes. The less you put on your\nplate, the better. A good example of a well-written Vue app is the [registry\nimage list](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/14303).\n\n\n### I want to use jQuery with Vue\n\n\nDuring new development, this question kept popping up.\n\n> Is it ever OK to mix jQuery with VueJS?\n\n\nWe are not talking about using [Select2](https://select2.org/), which is a\njQuery library. We are talking about the need to query the DOM. We had\ndiscussions about using jQuery and the following was proposed:\n\n\n> Using jQuery is OK, but only for querying.\n\n\nAt first I had several discussions about using jQuery with Vue. Some had\nsaid it might be OK, but only in read-only (querying) situations. However,\nafter doing the research, we found that it is **not** a good idea to use\njQuery with Vue. There will always be a better solution. We found that if\nyou ever find yourself needing to query to DOM within a Vue architecture,\nthen you are doing something wrong.\n\n\nIf one were to hypothetically use jQuery for only the tiniest querying\nsituations, one would have to quantify those situations. You should instead\nswear off querying the DOM when in Vue.\n\n\nInstead of querying, you will find that using the `store` in combination\nwith the server-side code is usually a much simpler answer. The server can\nprovide validity to your data that you cannot provide on the client side.\nFor the most part, we find that the less we have to fool with the data on\nthe client side the better. That's not to say it's never OK to modify the\ndata on the client side, but that it isn't usually the cleanest solution. At\nGitLab we use querying only to grab endpoints from the `data` attribute of\nour main element, but we don't use jQuery, we use `el.dataset`. At GitLab,\nwe (the Frontend people) talk with the Backend people to ensure the\nstructure of the data we will be consuming. In that way, both the Frontend\nteam and the Backend team can be in control.\n\n\n#### Example situation:\n\n\nCheck out this issue:\n\n\n![issue](https://about.gitlab.com/images/vue_2017/issue.png){: .shadow}\n\n\nWe now render all issue comments in Vue. An example of a situation where we\nwanted to use jQuery was during the rewrite of the\nedit-the-last-user-comment feature. When someone presses that `up` key on\ntheir keyboard from an empty new comment `textarea` (at the very bottom of\nthe page) we allow them to edit the last comment they created, just like in\nSlack. Not just the last comment, but the last comment *they created*. We\nmarked the last user comment in the picture in red. Of course there is a\ntime crunch. Then someone might say,\n\n\n> Can't we just do a quick solution here and fix it later?\n\n\nSurely you *could* query the DOM for this. A better solution, in this case,\nis to let the backend developers mark the last user comment in the JSON they\nreturn. Backend developers have direct access to the database, which means\nthey may be able to optimize the code. Then no client-side work has to be\ndone at all, in this case. Someone has to do the work to mark the last user\ncomment. In this case the solution is just finding the right person for the\njob. Once you have that data from the server, the comment is in your\n`store`, ready for your easy access. You can do anything now. The world is\nyour oyster.\n\n\nIf you find yourself querying the DOM, \"just this one time\" 😉, there is\nalways a better solution.\n\n\n### The proper Vue app\n\n\nEvery Vue bundle needs one store, one service, and always has one entry\npoint. Your entry point component is the only container component and every\nother component is presentational. All this information is in our Vue docs.\n\n\nYou can start out with a single `div`.\n\n\n```html\n\n\u003C!--HAML-->\n\n.js-vue-app{ data: { endpoint: 'foo' }}\n\n\n\u003C!--HTML-->\n\n\u003Cdiv class=\"js-vue-app\" data-endpoint=\"foo\">\u003C/div>\n\n```\n\nYou can pass your endpoints in through the data attributes. Vue can then\ncall these endpoints with an HTTP client of your choice.\n\n\nYou don't want to do any URL building in client-side JavaScript. Make sure\nyou pass in all your server-built URLs through endpoints. When writing Vue\nit's important to let the server do what it should.\n\n\n## Improve performance\n\n\nWe recently rewrote our issue comments in Vue. The issue comments were\npreviously written in Haml, jQuery, and Rails. We had a bottleneck because\nwe were not loading the comments asynchronously. A quick solution is to load\ncomments via ajax and populate comments after the page loads. One way to\nmake a page load faster is to not block the page with heavy items and load\nthem after.\n\n\n![comments.png](https://about.gitlab.com/images/vue_2017/comments.png){:\n.shadow}\n\n\nWhat we love is that one day we turned on the new comments and some people\ndidn't know that we had refactored it. As a result of the refactor our issue\npages load much faster, and there is less jank.\n\n\nLoading the comments on the issue page is now streamlined and now individual\nissues load much faster. In the past, an issue page could have tens of\nthousands of event listeners. Our previous code was not properly removing\nand keeping track of event listeners. Those massive event listeners (along\nwith other problems) created jank, so scrolling the page was choppy with\nmany comments. We removed jQuery and added in Vue and focused on improving\nthe performance. You can clearly see and feel that the page is much faster.\nHowever, our work to improve the performance has just begun. This rewrite\nsets the foundation for performance improvements that are easier to write,\nbecause the code is much more maintainable. Previously the code was hard to\nmaintain. Now the issue comments code is properly separated and\n\"componentized.\"\n\n\nWith these new improvements, as well as other parallel improvements, e.g.\nloading images on scroll, we were able to make the page load and perform\nfaster.\n\n\n![speed.png](https://about.gitlab.com/images/vue_2017/speed.png){: .shadow}\n\n\nRefactoring is that word that a new, super-green developer mentions on day\none when they suggest to rewrite everything in Angular. That hasn't happened\nat GitLab. Our frontend devs tend to be very conservative, which is a very\ngood thing. Which begs the question, why does it seems like [everyone is\nalways refactoring](https://reasonml.github.io/community/blog/#reason-3)?\nWhat are they trying to achieve? I can only speak for GitLab. What do we\nwant to achieve with a refactor? In reality it's going to cost a lot of\nmoney. The costs are:\n\n\n1. Cost of doing the refactoring.\n\n1. Cost of testing the change.\n\n1. Cost of updating tests and documentation.\n\n\nYou also have more risk:\n\n\n1. Risk of introducing bugs.\n\n1. Risk of taking on a huge task that you can't finish.\n\n1. Risk of not achieving the quality/improvements you intended.\n\n\nOur goals are:\n\n\n**Goal #1**: Make the code more maintainable. We want to make the process of\nadding new features easier. In the long term this refactor will save us\ntime, but it takes a significant amount of time to recoup the time spent\nrefactoring. The hard truth may be that a refactor usually does not save you\ntime, but can save you stress.\n\n\n**Goal #2**: What it can do, if done right, is make developers happy.\nNothing gives your team more horsepower than a happy, excited coder. A\nstressed-out coder will want to stop coding; an excited coder will not want\nto stop. A happy coder saves the most time.\n\n\nTo meet our goal our next step is to refactor the merge request comments\nsection. Our merge request comments are massively slow for merge requests\nwith lots of comments. The comments become slower and start to be less\nresponsive at around 200 comments. The diffs are slow as well. There are a\nton of reasons for this, one of which is that JavaScript is causing multiple\nreflows that take tons of time. We could refactor this and have already put\nin a fix, but this isn't a long-term solution.  In the case of a huge MR,\nthere was code that was causing a reflow that [takes over eight\nseconds](https://gitlab.com/gitlab-org/gitlab-ce/issues/39332)! This is now\nfixed. In this\n[image](https://gitlab.com/gitlab-org/gitlab-ce/uploads/e18856a1544d4d0e6420d11fd0479af7/ss__2017-10-20_at_1.41.04_PM.png) \nyou can see there is other stuff slowing things down. Clearly there is a lot\nof work to do here. Our biggest problem is that the code is not\nmaintainable, which means that fixes take longer. A refactor into Vue will\nprovide some great initial speed improvements, and lay the groundwork for\neasier improvements in the future.\n\n\nThere is so much work to do at GitLab. If you want to be a part of exploring\nthe massive catacombs of GitLab and writing awesome code and if you are\ninterested in helping out our Frontend team, then\n[apply](https://handbook.gitlab.com/job-families/engineering/development/frontend/).\n","engineering",[23,24],"frontend","inside GitLab",{"slug":26,"featured":6,"template":27},"gitlab-vue-one-year-later","BlogPost","content:en-us:blog:gitlab-vue-one-year-later.yml","yaml","Gitlab Vue One Year Later","content","en-us/blog/gitlab-vue-one-year-later.yml","en-us/blog/gitlab-vue-one-year-later","yml",{"_path":36,"_dir":37,"_draft":6,"_partial":6,"_locale":7,"data":38,"_id":460,"_type":29,"title":461,"_source":31,"_file":462,"_stem":463,"_extension":34},"/shared/en-us/main-navigation","en-us",{"logo":39,"freeTrial":44,"sales":49,"login":54,"items":59,"search":391,"minimal":422,"duo":441,"pricingDeployment":450},{"config":40},{"href":41,"dataGaName":42,"dataGaLocation":43},"/","gitlab logo","header",{"text":45,"config":46},"Get free trial",{"href":47,"dataGaName":48,"dataGaLocation":43},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com&glm_content=default-saas-trial/","free trial",{"text":50,"config":51},"Talk to sales",{"href":52,"dataGaName":53,"dataGaLocation":43},"/sales/","sales",{"text":55,"config":56},"Sign in",{"href":57,"dataGaName":58,"dataGaLocation":43},"https://gitlab.com/users/sign_in/","sign in",[60,104,202,207,312,372],{"text":61,"config":62,"cards":64,"footer":87},"Platform",{"dataNavLevelOne":63},"platform",[65,71,79],{"title":61,"description":66,"link":67},"The most comprehensive AI-powered DevSecOps Platform",{"text":68,"config":69},"Explore our Platform",{"href":70,"dataGaName":63,"dataGaLocation":43},"/platform/",{"title":72,"description":73,"link":74},"GitLab Duo (AI)","Build software faster with AI at every stage of development",{"text":75,"config":76},"Meet GitLab Duo",{"href":77,"dataGaName":78,"dataGaLocation":43},"/gitlab-duo/","gitlab duo ai",{"title":80,"description":81,"link":82},"Why GitLab","10 reasons why Enterprises choose GitLab",{"text":83,"config":84},"Learn more",{"href":85,"dataGaName":86,"dataGaLocation":43},"/why-gitlab/","why gitlab",{"title":88,"items":89},"Get started with",[90,95,100],{"text":91,"config":92},"Platform Engineering",{"href":93,"dataGaName":94,"dataGaLocation":43},"/solutions/platform-engineering/","platform engineering",{"text":96,"config":97},"Developer Experience",{"href":98,"dataGaName":99,"dataGaLocation":43},"/developer-experience/","Developer experience",{"text":101,"config":102},"MLOps",{"href":103,"dataGaName":101,"dataGaLocation":43},"/topics/devops/the-role-of-ai-in-devops/",{"text":105,"left":106,"config":107,"link":109,"lists":113,"footer":184},"Product",true,{"dataNavLevelOne":108},"solutions",{"text":110,"config":111},"View all Solutions",{"href":112,"dataGaName":108,"dataGaLocation":43},"/solutions/",[114,139,163],{"title":115,"description":116,"link":117,"items":122},"Automation","CI/CD and automation to accelerate deployment",{"config":118},{"icon":119,"href":120,"dataGaName":121,"dataGaLocation":43},"AutomatedCodeAlt","/solutions/delivery-automation/","automated software delivery",[123,127,131,135],{"text":124,"config":125},"CI/CD",{"href":126,"dataGaLocation":43,"dataGaName":124},"/solutions/continuous-integration/",{"text":128,"config":129},"AI-Assisted Development",{"href":77,"dataGaLocation":43,"dataGaName":130},"AI assisted development",{"text":132,"config":133},"Source Code Management",{"href":134,"dataGaLocation":43,"dataGaName":132},"/solutions/source-code-management/",{"text":136,"config":137},"Automated Software Delivery",{"href":120,"dataGaLocation":43,"dataGaName":138},"Automated software delivery",{"title":140,"description":141,"link":142,"items":147},"Security","Deliver code faster without compromising security",{"config":143},{"href":144,"dataGaName":145,"dataGaLocation":43,"icon":146},"/solutions/security-compliance/","security and compliance","ShieldCheckLight",[148,153,158],{"text":149,"config":150},"Application Security Testing",{"href":151,"dataGaName":152,"dataGaLocation":43},"/solutions/application-security-testing/","Application security testing",{"text":154,"config":155},"Software Supply Chain Security",{"href":156,"dataGaLocation":43,"dataGaName":157},"/solutions/supply-chain/","Software supply chain security",{"text":159,"config":160},"Software Compliance",{"href":161,"dataGaName":162,"dataGaLocation":43},"/solutions/software-compliance/","software compliance",{"title":164,"link":165,"items":170},"Measurement",{"config":166},{"icon":167,"href":168,"dataGaName":169,"dataGaLocation":43},"DigitalTransformation","/solutions/visibility-measurement/","visibility and measurement",[171,175,179],{"text":172,"config":173},"Visibility & Measurement",{"href":168,"dataGaLocation":43,"dataGaName":174},"Visibility and Measurement",{"text":176,"config":177},"Value Stream Management",{"href":178,"dataGaLocation":43,"dataGaName":176},"/solutions/value-stream-management/",{"text":180,"config":181},"Analytics & Insights",{"href":182,"dataGaLocation":43,"dataGaName":183},"/solutions/analytics-and-insights/","Analytics and insights",{"title":185,"items":186},"GitLab for",[187,192,197],{"text":188,"config":189},"Enterprise",{"href":190,"dataGaLocation":43,"dataGaName":191},"/enterprise/","enterprise",{"text":193,"config":194},"Small Business",{"href":195,"dataGaLocation":43,"dataGaName":196},"/small-business/","small business",{"text":198,"config":199},"Public Sector",{"href":200,"dataGaLocation":43,"dataGaName":201},"/solutions/public-sector/","public sector",{"text":203,"config":204},"Pricing",{"href":205,"dataGaName":206,"dataGaLocation":43,"dataNavLevelOne":206},"/pricing/","pricing",{"text":208,"config":209,"link":211,"lists":215,"feature":299},"Resources",{"dataNavLevelOne":210},"resources",{"text":212,"config":213},"View all resources",{"href":214,"dataGaName":210,"dataGaLocation":43},"/resources/",[216,249,271],{"title":217,"items":218},"Getting started",[219,224,229,234,239,244],{"text":220,"config":221},"Install",{"href":222,"dataGaName":223,"dataGaLocation":43},"/install/","install",{"text":225,"config":226},"Quick start guides",{"href":227,"dataGaName":228,"dataGaLocation":43},"/get-started/","quick setup checklists",{"text":230,"config":231},"Learn",{"href":232,"dataGaLocation":43,"dataGaName":233},"https://university.gitlab.com/","learn",{"text":235,"config":236},"Product documentation",{"href":237,"dataGaName":238,"dataGaLocation":43},"https://docs.gitlab.com/","product documentation",{"text":240,"config":241},"Best practice videos",{"href":242,"dataGaName":243,"dataGaLocation":43},"/getting-started-videos/","best practice videos",{"text":245,"config":246},"Integrations",{"href":247,"dataGaName":248,"dataGaLocation":43},"/integrations/","integrations",{"title":250,"items":251},"Discover",[252,257,261,266],{"text":253,"config":254},"Customer success stories",{"href":255,"dataGaName":256,"dataGaLocation":43},"/customers/","customer success stories",{"text":258,"config":259},"Blog",{"href":260,"dataGaName":5,"dataGaLocation":43},"/blog/",{"text":262,"config":263},"Remote",{"href":264,"dataGaName":265,"dataGaLocation":43},"https://handbook.gitlab.com/handbook/company/culture/all-remote/","remote",{"text":267,"config":268},"TeamOps",{"href":269,"dataGaName":270,"dataGaLocation":43},"/teamops/","teamops",{"title":272,"items":273},"Connect",[274,279,284,289,294],{"text":275,"config":276},"GitLab Services",{"href":277,"dataGaName":278,"dataGaLocation":43},"/services/","services",{"text":280,"config":281},"Community",{"href":282,"dataGaName":283,"dataGaLocation":43},"/community/","community",{"text":285,"config":286},"Forum",{"href":287,"dataGaName":288,"dataGaLocation":43},"https://forum.gitlab.com/","forum",{"text":290,"config":291},"Events",{"href":292,"dataGaName":293,"dataGaLocation":43},"/events/","events",{"text":295,"config":296},"Partners",{"href":297,"dataGaName":298,"dataGaLocation":43},"/partners/","partners",{"backgroundColor":300,"textColor":301,"text":302,"image":303,"link":307},"#2f2a6b","#fff","Insights for the future of software development",{"altText":304,"config":305},"the source promo card",{"src":306},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758208064/dzl0dbift9xdizyelkk4.svg",{"text":308,"config":309},"Read the latest",{"href":310,"dataGaName":311,"dataGaLocation":43},"/the-source/","the source",{"text":313,"config":314,"lists":316},"Company",{"dataNavLevelOne":315},"company",[317],{"items":318},[319,324,330,332,337,342,347,352,357,362,367],{"text":320,"config":321},"About",{"href":322,"dataGaName":323,"dataGaLocation":43},"/company/","about",{"text":325,"config":326,"footerGa":329},"Jobs",{"href":327,"dataGaName":328,"dataGaLocation":43},"/jobs/","jobs",{"dataGaName":328},{"text":290,"config":331},{"href":292,"dataGaName":293,"dataGaLocation":43},{"text":333,"config":334},"Leadership",{"href":335,"dataGaName":336,"dataGaLocation":43},"/company/team/e-group/","leadership",{"text":338,"config":339},"Team",{"href":340,"dataGaName":341,"dataGaLocation":43},"/company/team/","team",{"text":343,"config":344},"Handbook",{"href":345,"dataGaName":346,"dataGaLocation":43},"https://handbook.gitlab.com/","handbook",{"text":348,"config":349},"Investor relations",{"href":350,"dataGaName":351,"dataGaLocation":43},"https://ir.gitlab.com/","investor relations",{"text":353,"config":354},"Trust Center",{"href":355,"dataGaName":356,"dataGaLocation":43},"/security/","trust center",{"text":358,"config":359},"AI Transparency Center",{"href":360,"dataGaName":361,"dataGaLocation":43},"/ai-transparency-center/","ai transparency center",{"text":363,"config":364},"Newsletter",{"href":365,"dataGaName":366,"dataGaLocation":43},"/company/contact/","newsletter",{"text":368,"config":369},"Press",{"href":370,"dataGaName":371,"dataGaLocation":43},"/press/","press",{"text":373,"config":374,"lists":375},"Contact us",{"dataNavLevelOne":315},[376],{"items":377},[378,381,386],{"text":50,"config":379},{"href":52,"dataGaName":380,"dataGaLocation":43},"talk to sales",{"text":382,"config":383},"Get help",{"href":384,"dataGaName":385,"dataGaLocation":43},"/support/","get help",{"text":387,"config":388},"Customer portal",{"href":389,"dataGaName":390,"dataGaLocation":43},"https://customers.gitlab.com/customers/sign_in/","customer portal",{"close":392,"login":393,"suggestions":400},"Close",{"text":394,"link":395},"To search repositories and projects, login to",{"text":396,"config":397},"gitlab.com",{"href":57,"dataGaName":398,"dataGaLocation":399},"search login","search",{"text":401,"default":402},"Suggestions",[403,405,409,411,415,419],{"text":72,"config":404},{"href":77,"dataGaName":72,"dataGaLocation":399},{"text":406,"config":407},"Code Suggestions (AI)",{"href":408,"dataGaName":406,"dataGaLocation":399},"/solutions/code-suggestions/",{"text":124,"config":410},{"href":126,"dataGaName":124,"dataGaLocation":399},{"text":412,"config":413},"GitLab on AWS",{"href":414,"dataGaName":412,"dataGaLocation":399},"/partners/technology-partners/aws/",{"text":416,"config":417},"GitLab on Google Cloud",{"href":418,"dataGaName":416,"dataGaLocation":399},"/partners/technology-partners/google-cloud-platform/",{"text":420,"config":421},"Why GitLab?",{"href":85,"dataGaName":420,"dataGaLocation":399},{"freeTrial":423,"mobileIcon":428,"desktopIcon":433,"secondaryButton":436},{"text":424,"config":425},"Start free trial",{"href":426,"dataGaName":48,"dataGaLocation":427},"https://gitlab.com/-/trials/new/","nav",{"altText":429,"config":430},"Gitlab Icon",{"src":431,"dataGaName":432,"dataGaLocation":427},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203874/jypbw1jx72aexsoohd7x.svg","gitlab icon",{"altText":429,"config":434},{"src":435,"dataGaName":432,"dataGaLocation":427},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203875/gs4c8p8opsgvflgkswz9.svg",{"text":437,"config":438},"Get Started",{"href":439,"dataGaName":440,"dataGaLocation":427},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com/compare/gitlab-vs-github/","get started",{"freeTrial":442,"mobileIcon":446,"desktopIcon":448},{"text":443,"config":444},"Learn more about GitLab Duo",{"href":77,"dataGaName":445,"dataGaLocation":427},"gitlab duo",{"altText":429,"config":447},{"src":431,"dataGaName":432,"dataGaLocation":427},{"altText":429,"config":449},{"src":435,"dataGaName":432,"dataGaLocation":427},{"freeTrial":451,"mobileIcon":456,"desktopIcon":458},{"text":452,"config":453},"Back to pricing",{"href":205,"dataGaName":454,"dataGaLocation":427,"icon":455},"back to pricing","GoBack",{"altText":429,"config":457},{"src":431,"dataGaName":432,"dataGaLocation":427},{"altText":429,"config":459},{"src":435,"dataGaName":432,"dataGaLocation":427},"content:shared:en-us:main-navigation.yml","Main Navigation","shared/en-us/main-navigation.yml","shared/en-us/main-navigation",{"_path":465,"_dir":37,"_draft":6,"_partial":6,"_locale":7,"title":466,"button":467,"image":472,"config":476,"_id":478,"_type":29,"_source":31,"_file":479,"_stem":480,"_extension":34},"/shared/en-us/banner","is now in public beta!",{"text":468,"config":469},"Try the Beta",{"href":470,"dataGaName":471,"dataGaLocation":43},"/gitlab-duo/agent-platform/","duo banner",{"altText":473,"config":474},"GitLab Duo Agent Platform",{"src":475},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1753720689/somrf9zaunk0xlt7ne4x.svg",{"layout":477},"release","content:shared:en-us:banner.yml","shared/en-us/banner.yml","shared/en-us/banner",{"_path":482,"_dir":37,"_draft":6,"_partial":6,"_locale":7,"data":483,"_id":687,"_type":29,"title":688,"_source":31,"_file":689,"_stem":690,"_extension":34},"/shared/en-us/main-footer",{"text":484,"source":485,"edit":491,"contribute":496,"config":501,"items":506,"minimal":679},"Git is a trademark of Software Freedom Conservancy and our use of 'GitLab' is under license",{"text":486,"config":487},"View page source",{"href":488,"dataGaName":489,"dataGaLocation":490},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/","page source","footer",{"text":492,"config":493},"Edit this page",{"href":494,"dataGaName":495,"dataGaLocation":490},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/content/","web ide",{"text":497,"config":498},"Please contribute",{"href":499,"dataGaName":500,"dataGaLocation":490},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/CONTRIBUTING.md/","please contribute",{"twitter":502,"facebook":503,"youtube":504,"linkedin":505},"https://twitter.com/gitlab","https://www.facebook.com/gitlab","https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg","https://www.linkedin.com/company/gitlab-com",[507,530,586,615,649],{"title":61,"links":508,"subMenu":513},[509],{"text":510,"config":511},"DevSecOps platform",{"href":70,"dataGaName":512,"dataGaLocation":490},"devsecops platform",[514],{"title":203,"links":515},[516,520,525],{"text":517,"config":518},"View plans",{"href":205,"dataGaName":519,"dataGaLocation":490},"view plans",{"text":521,"config":522},"Why Premium?",{"href":523,"dataGaName":524,"dataGaLocation":490},"/pricing/premium/","why premium",{"text":526,"config":527},"Why Ultimate?",{"href":528,"dataGaName":529,"dataGaLocation":490},"/pricing/ultimate/","why ultimate",{"title":531,"links":532},"Solutions",[533,538,540,542,547,552,556,559,563,568,570,573,576,581],{"text":534,"config":535},"Digital transformation",{"href":536,"dataGaName":537,"dataGaLocation":490},"/topics/digital-transformation/","digital transformation",{"text":149,"config":539},{"href":151,"dataGaName":149,"dataGaLocation":490},{"text":138,"config":541},{"href":120,"dataGaName":121,"dataGaLocation":490},{"text":543,"config":544},"Agile development",{"href":545,"dataGaName":546,"dataGaLocation":490},"/solutions/agile-delivery/","agile delivery",{"text":548,"config":549},"Cloud transformation",{"href":550,"dataGaName":551,"dataGaLocation":490},"/topics/cloud-native/","cloud transformation",{"text":553,"config":554},"SCM",{"href":134,"dataGaName":555,"dataGaLocation":490},"source code management",{"text":124,"config":557},{"href":126,"dataGaName":558,"dataGaLocation":490},"continuous integration & delivery",{"text":560,"config":561},"Value stream management",{"href":178,"dataGaName":562,"dataGaLocation":490},"value stream management",{"text":564,"config":565},"GitOps",{"href":566,"dataGaName":567,"dataGaLocation":490},"/solutions/gitops/","gitops",{"text":188,"config":569},{"href":190,"dataGaName":191,"dataGaLocation":490},{"text":571,"config":572},"Small business",{"href":195,"dataGaName":196,"dataGaLocation":490},{"text":574,"config":575},"Public sector",{"href":200,"dataGaName":201,"dataGaLocation":490},{"text":577,"config":578},"Education",{"href":579,"dataGaName":580,"dataGaLocation":490},"/solutions/education/","education",{"text":582,"config":583},"Financial services",{"href":584,"dataGaName":585,"dataGaLocation":490},"/solutions/finance/","financial services",{"title":208,"links":587},[588,590,592,594,597,599,601,603,605,607,609,611,613],{"text":220,"config":589},{"href":222,"dataGaName":223,"dataGaLocation":490},{"text":225,"config":591},{"href":227,"dataGaName":228,"dataGaLocation":490},{"text":230,"config":593},{"href":232,"dataGaName":233,"dataGaLocation":490},{"text":235,"config":595},{"href":237,"dataGaName":596,"dataGaLocation":490},"docs",{"text":258,"config":598},{"href":260,"dataGaName":5,"dataGaLocation":490},{"text":253,"config":600},{"href":255,"dataGaName":256,"dataGaLocation":490},{"text":262,"config":602},{"href":264,"dataGaName":265,"dataGaLocation":490},{"text":275,"config":604},{"href":277,"dataGaName":278,"dataGaLocation":490},{"text":267,"config":606},{"href":269,"dataGaName":270,"dataGaLocation":490},{"text":280,"config":608},{"href":282,"dataGaName":283,"dataGaLocation":490},{"text":285,"config":610},{"href":287,"dataGaName":288,"dataGaLocation":490},{"text":290,"config":612},{"href":292,"dataGaName":293,"dataGaLocation":490},{"text":295,"config":614},{"href":297,"dataGaName":298,"dataGaLocation":490},{"title":313,"links":616},[617,619,621,623,625,627,629,633,638,640,642,644],{"text":320,"config":618},{"href":322,"dataGaName":315,"dataGaLocation":490},{"text":325,"config":620},{"href":327,"dataGaName":328,"dataGaLocation":490},{"text":333,"config":622},{"href":335,"dataGaName":336,"dataGaLocation":490},{"text":338,"config":624},{"href":340,"dataGaName":341,"dataGaLocation":490},{"text":343,"config":626},{"href":345,"dataGaName":346,"dataGaLocation":490},{"text":348,"config":628},{"href":350,"dataGaName":351,"dataGaLocation":490},{"text":630,"config":631},"Sustainability",{"href":632,"dataGaName":630,"dataGaLocation":490},"/sustainability/",{"text":634,"config":635},"Diversity, inclusion and belonging (DIB)",{"href":636,"dataGaName":637,"dataGaLocation":490},"/diversity-inclusion-belonging/","Diversity, inclusion and belonging",{"text":353,"config":639},{"href":355,"dataGaName":356,"dataGaLocation":490},{"text":363,"config":641},{"href":365,"dataGaName":366,"dataGaLocation":490},{"text":368,"config":643},{"href":370,"dataGaName":371,"dataGaLocation":490},{"text":645,"config":646},"Modern Slavery Transparency Statement",{"href":647,"dataGaName":648,"dataGaLocation":490},"https://handbook.gitlab.com/handbook/legal/modern-slavery-act-transparency-statement/","modern slavery transparency statement",{"title":650,"links":651},"Contact Us",[652,655,657,659,664,669,674],{"text":653,"config":654},"Contact an expert",{"href":52,"dataGaName":53,"dataGaLocation":490},{"text":382,"config":656},{"href":384,"dataGaName":385,"dataGaLocation":490},{"text":387,"config":658},{"href":389,"dataGaName":390,"dataGaLocation":490},{"text":660,"config":661},"Status",{"href":662,"dataGaName":663,"dataGaLocation":490},"https://status.gitlab.com/","status",{"text":665,"config":666},"Terms of use",{"href":667,"dataGaName":668,"dataGaLocation":490},"/terms/","terms of use",{"text":670,"config":671},"Privacy statement",{"href":672,"dataGaName":673,"dataGaLocation":490},"/privacy/","privacy statement",{"text":675,"config":676},"Cookie preferences",{"dataGaName":677,"dataGaLocation":490,"id":678,"isOneTrustButton":106},"cookie preferences","ot-sdk-btn",{"items":680},[681,683,685],{"text":665,"config":682},{"href":667,"dataGaName":668,"dataGaLocation":490},{"text":670,"config":684},{"href":672,"dataGaName":673,"dataGaLocation":490},{"text":675,"config":686},{"dataGaName":677,"dataGaLocation":490,"id":678,"isOneTrustButton":106},"content:shared:en-us:main-footer.yml","Main Footer","shared/en-us/main-footer.yml","shared/en-us/main-footer",[692],{"_path":693,"_dir":694,"_draft":6,"_partial":6,"_locale":7,"content":695,"config":698,"_id":700,"_type":29,"title":18,"_source":31,"_file":701,"_stem":702,"_extension":34},"/en-us/blog/authors/jacob-schatz","authors",{"name":18,"config":696},{"headshot":7,"ctfId":697},"jschatz1",{"template":699},"BlogAuthor","content:en-us:blog:authors:jacob-schatz.yml","en-us/blog/authors/jacob-schatz.yml","en-us/blog/authors/jacob-schatz",{"_path":704,"_dir":37,"_draft":6,"_partial":6,"_locale":7,"header":705,"eyebrow":706,"blurb":707,"button":708,"secondaryButton":712,"_id":714,"_type":29,"title":715,"_source":31,"_file":716,"_stem":717,"_extension":34},"/shared/en-us/next-steps","Start shipping better software faster","50%+ of the Fortune 100 trust GitLab","See what your team can do with the intelligent\n\n\nDevSecOps platform.\n",{"text":45,"config":709},{"href":710,"dataGaName":48,"dataGaLocation":711},"https://gitlab.com/-/trial_registrations/new?glm_content=default-saas-trial&glm_source=about.gitlab.com/","feature",{"text":50,"config":713},{"href":52,"dataGaName":53,"dataGaLocation":711},"content:shared:en-us:next-steps.yml","Next Steps","shared/en-us/next-steps.yml","shared/en-us/next-steps",1758326257280]