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