[{"data":1,"prerenderedAt":762},["ShallowReactive",2],{"/en-us/blog/environment-friction-cycle":3,"navigation-en-us":37,"banner-en-us":465,"footer-en-us":482,"Darwin Sanoy":726,"next-steps-en-us":741,"footer-source-/en-us/blog/environment-friction-cycle/":756},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"seo":8,"content":16,"config":27,"_id":30,"_type":31,"title":32,"_source":33,"_file":34,"_stem":35,"_extension":36},"/en-us/blog/environment-friction-cycle","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 GitLab eliminates value stream friction in dev environments","It is important to have the complete picture of scaled effects in view when designing automation.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749682507/Blog/Hero%20Images/sandeep-singh-3KbACriapqQ-unsplash.jpg","https://about.gitlab.com/blog/environment-friction-cycle","https://about.gitlab.com","article","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How GitLab can eliminate the massive value stream friction of developer environment provisioning and cleanup\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Darwin Sanoy\"}],\n        \"datePublished\": \"2022-11-17\",\n      }",{"title":17,"description":10,"authors":18,"heroImage":11,"date":20,"body":21,"category":22,"tags":23},"How GitLab can eliminate the massive value stream friction of developer environment provisioning and cleanup",[19],"Darwin Sanoy","2022-11-17","A strong DevOps value stream drives developer empowerment as far left as\npossible. In GitLab, this is embodied in per-feature branch merge requests\nthat are rich with automated code quality and defect information - including\nnot only findings - but automated remediation capabilities and\ncollaboration. Some defects and code quality issues can only be found by\nanalyzing a running copy of the application, including DAST, IAST, fuzzing\nand many others. GitLab has built a fully automated, seamless developer\nenvironment lifecycle management approach right into the developer\nexperience. In fact, it’s so seamlessly built-in, it can be easy to overlook\nhow critical developer environment lifecycle management is. This article\nwill highlight why and how GitLab adds value using developer environment\nautomation. In addition, while GitLab provides out of the box developer\nenvironment lifecycle management for Kubernetes, this article demonstrates\nan approach and a working example of how to extend that capability to other\ncommon cloud-based application framework PaaS offerings.\n\n\n## Provisioning of development environments is generally a negative feedback\nloop\n\n\nIn a prior job, I worked on a DevOps transformation team that supported\nmultiple massive shared development environments in AWS. They were\naccessible to more than 4,000 developers working to build more than 100 SaaS\napplications and utility stacks. In the journey to the AWS Cloud, each\ndevelopment team took ownership of the automation required to deploy their\napplications. Since developers were able to self-service, over time this\nsolved the problem of development friction generated by waiting for\nenvironments to be provisioned for testing, feature experiments, integration\nexperiments, etc. \n\n\nHowever, the other half of the problem then ballooned - environment sprawl -\nwith an untold number of environments idling without management and without\nknowledge of when they could be torn down. Over time the development\nenvironment cost became a significant multiple of production costs. The\ncloud has solved problems with environment provisioning bottlenecks due to\nhardware acquisition and provisioning, but this can also inadvertently fuel\nthe high costs of unmanaged sprawl. This problem understandably causes\norganizations to raise administrative barriers to new development\nenvironments.\n\n\nIn many organizations this becomes a vicious cycle - most especially if\ndeveloper environments are operated by a different team, or worse, on an\nindependent budget. Environment justification friction usually comes quickly\nafter discovering the true cost of the current running environments.\nDevelopers then have to justify the need for new environment requests and\nthey have to make the gravest of promises to disband the environment as soon\nas they are done. Another friction arises when a separate group is tasked\nwith cost controls and environment provisioning and cleanup. This introduces\nfriction in the form of administrative and work queueing delays.\nCoordination friction also crops up because an accurate understanding of\nexactly what is needed for an environment can be challenging to convey. When\nmistakes are made or key information is missing, developers must go back and\nforth on support requests to get the configuration completely correct.\n\n\n## Partial automation can worsen the problem\n\n\nThat’s the first half of the environment lifecycle, but as I mentioned, even\nif that is fully automated and under the control of developers, the other\nhalf of the feedback loop comes into play. When a given development\nenvironment has fulfilled its initial justification reason, the team does\nnot want to destroy it because environments are so hard to justify and\ncreate. Then the sprawl starts and, of course, the barriers to new\nenvironments are raised even higher. This is a classic negative feedback\nloop.\n\n\nSystems theory shows us that sometimes there are just a few key factors in\nstopping or even reversing a negative feedback loop. Lets take this specific\nproblem apart and talk about how GitLab solves for it.\n\n\n## Treat developer environments as a complete lifecycle\n\n\nIn the prior example it is evident that by leaving out the last stage of the\nenvironment lifecycle - retirement or tear down - we still end up with a\nnegative feedback loop. Removing provisioning friction actually makes the\nproblem worse if retirement friction is not also addressed at the same time.\nSolutions to this problem need to address the entire lifecycle to avoid\nimpacting value stream velocity. Neglecting or avoiding the retirement stage\nof a lifecycle is a common problem across all types of systems. In contrast,\nby addressing the entire lifecycle we can transform it from being a negative\nfeedback loop to a managed lifecycle.\n\n\n## The problems of who and when\n\n\nBuried inside the insidious friction loop are a couple key coordination\nproblems we’ll call “Who and When.” Basically, \"Who\" should create\nenvironments and \"When\" should they be created to ensure reasonable cost\noptimization? Then again, _Who_ should cleanup environments and _When_ do\nyou know that the environment is no longer needed with certainty? Even with\nhighly collaborative teams working hard together for maximum business value,\nthese questions present a difficulty that frequently results in environments\nrunning for a long time before they are used and after they are no longer\nneeded. The knowledge of appropriate timing plays a critical role in gaining\ncontrol over this source of friction.\n\n\n## The problem of non-immutable development environments\n\n\nFriction in environment lifecycle management creates a substantial knock-on\nproblem associated with long-lived environments. Long-lived environments\nthat are updated multiple times for various independent projects start to\naccumulate configuration rot; they become snowflakes with small changes that\nare left over from non-implemented experiments, software or configuration\nremovals, and other irrelevant bits and pieces. Immutability is the practice\nof not doing “in place” updates to a computing element, but rather\ndestroying it and replacing it with a fresh, built-from-scratch, element.\nDocker has made this concept very accepted and effective in production\nworkloads, but development environments frequently do not have this\nattribute due to automating without the design constraint of immutability,\nso they are updated in-place for reuse by various initiatives. If the\nenvironment lifecycle is not fully automated, it impossible to make them\nworkable on a per-feature branch basis.\n\n\n## The problem of non-isolated development environments \n\n\nWhen environments are manually provisioned or when there is a lot of cost or\nadministrative friction to setting them up, environment sharing becomes more\ncommon place. This creates sharing contention at many levels. Waiting to\nschedule into use an environment, pressure to complete work quickly so\nothers can use the environment, and restrictions on the types of changes\nthat can be made to shared environments are just some of the common sharing\ncontention elements that arise. If environments can be isolated, then\nsharing contention friction evaporates. Pushing this to the extreme of a\nper-feature branch granularity brings many benefits, but is also difficult.\n\n\n## Effect on the development value stream\n\n\nThe effect that a friction-filled environment lifecycle has on the value\nstream can be immense - how many stories have you heard of projects waylaid\nfor weeks or months while waiting on environment provisioning? What about\ndefects shipped to production because a shared environment had left over\nconfiguration during testing? Frequently this friction is tolerated in the\nvalue stream because no one will argue that unlimited environment sprawl is\nan unwise use of company resources. We all turn off the lights in our home\nwhen we are no longer using a room and it is good business sense and good\nstewardship not to leave idle resources running at work.\n\n\nThe concept of good stewardship of planetary resources is actually becoming\nan architectural level priority in the technology sector. This is in\nevidenced in AWS’ [introduction of the “Sustainability” pillar to the AWS\nWell Architected principals in\n2021](https://aws.amazon.com/blogs/aws/sustainability-pillar-well-architected-framework/)\nand many other green initiatives in the technology sector.\n\n\nIt’s imperative that efforts to improve the development value stream\nconsider whether developer environment management friction is hampering the\nbreadth, depth and velocity of product management and software development.\n\n\n## Seamless and fully automated review environment lifecycle management\n\n\nWhat if this negative feedback loop could be stopped? What if new\nenvironments were seamless and automatically created right at the moment\nthey were needed? What if developers were completely happy to immediately\ntear down an environment when they were done because it takes no\njustification nor effort on their part to create new one at will?\n\n\nEnter GitLab Review Environments!\n\n\nGitLab review apps are created by the developer action of creating a new\nbranch. No humans are involved as the environment is deployed while the\ndeveloper is musing their first code changes on their branch.\n\n\nAs the developer pushes code updates the review apps are automatically\nupdated with the changes and all quality checks and security scanning are\nrun to ensure the developer understands that they introduced a vulnerability\nor quality defect. This is done within the shortest possible amount of time\nafter the defect was introduced.\n\n\nWhen the developer merges their code, the review app is automatically torn\ndown.\n\n\nThis seamless approach to developer environment provisioning and cleanup\naddresses enough of the critical factors in the negative feedback loop that\nit is effectively nullified.\n\n\nConsider:\n\n\n- Developer environment provisioning and cleanup are fully automated,\ntransparent, developer-initiated activities. They do not consume people nor\nhuman process resources, which are always legions slower and more expensive\nthan technology solutions.\n\n- Provisioning and cleanup timing are exactly synchronized with the\ndeveloper’s need, preventing inefficiencies in idle time before or after\nenvironment usage.\n\n- They are immutable on a new branch basis - a new branch always creates a\nnew environment from fresh copy of the latest code.\n\n- They are isolated - no sharing contention and no mixing of varying\nconfiguration.\n\n- They treat developer environments as a lifecycle.\n\n\nIt is so transparent that some developers may not even realize that their\nfeature branch has an isolated environment associated with it.\n\n\n## Hard dollar costs are important and opportunity costs are paramount\n\n\nGitLab environments positively contribute to the value stream in two\ncritical ways. First, the actual waste of idle machines is dramatically\nreduced. However, more importantly, all the human processes that end up\nbeing applied to managing that waste also disappear. Machines running in the\ncloud are only lost money. Inefficient use of people’s time carries a high\ndollar cost but it also carries a higher opportunity cost. There are so many\nvalue-generating activities people can do when their time is unencumbered by\ncost-control administration.\n\n\n## Multiplying the value stream contributions of developer review\nenvironments\n\n\nDeveloper environment friction is an industry-wide challenge and GitLab\nnearly eliminates the core problems of this feedback cycle. However, GitLab\nhas also gone way beyond simply addressing this problem by creating a lot of\nadditional value through seamless per-feature branch developer environments.\n\n\nHere is a visualization of where dynamic review environments plug into the\noverall GitLab developer workflow.\n\n\n![](https://about.gitlab.com/images/blogimages/environment-friction-lifecycle/gitlabenvironmentlifecycle.png)\n\n\n**Figure 1: Review environments with AWS Cloud Services**\n\n\nFigure 1 is showing GitLab’s full development cycle support with a little\nart of the possible thrown in around interfacing with AWS deployment\nservices. The green dashed arrow indicates that GitLab deploys a review\nenvironment when the branch is first created. Since the green arrow is part\nof the developer's iteration loop, the green arrow is also depicting that\nreview app updates are done on each code push. \n\n\nThe light purple box is showing that the iterative development and CI checks\nare all within the context of a merge request (MR), which provides a Single\nPane of Glass (SPOG) for all quality checks, vulnerabilities and\ncollaboration. Finally, when the merge is done, the review environment is\ncleaned up. The feature branch merge request is the furthest left that\nvisibility and remediation can be shifted. GitLab’s shifting of this into\nthe developer feature branch is what gives developers a semi-private\nopportunity to fix any quality or security findings with the specific code\nthey have added or updated.\n\n\nOne other thing to note here is that when GitLab CD code is engineered to\nhandle review environments, it is reused for all other preproduction and\nproduction environments. The set of AWS icons after the “Release” icon would\nbe using the same deployment code. However, if the GitLab CD code is\nengineered only around deploying to a set of static environments, it is not\nautomatically capable of review environments. Review environment support is\na superset of static environment support.\n\n\n## Review environments enable a profound shift left of visibility and\nremediation\n\n\nAt GitLab “shift left” is not just about “problem visibility” but also about\n“full developer enablement to resolve problems” while in-context. GitLab\nmerge requests provide critical elements that encourage developers to get\ninto a habit of defect remediation:\n\n\n- **Context** - Defect and vulnerability reporting is only for code the\ndeveloper changed in their branch and is tracked by the merge request (MR)\nfor that branch.\n\n- **Responsibility** - Since MRs and branches are associated to an\nindividual, it is evident to the developer (and the whole team) what defects\nwere introduced or discovered by which developers.\n\n- **Timing** - Developers become aware of defects nearly as soon as they are\nintroduced, not weeks or months after having integrated with other code. If\nthey were working on a physical product, we can envision that all the parts\nare still on the assembly bench.\n\n- **Visibility - Appropriately Local, Then Appropriately Global** -\nVisibility of defects is context specific. While a developer has an open MR\nthat is still a work in progress, they can be left alone to remedy\naccidentally-introduced defects with little concern from others because the\nvisibility is local to the MR. However, once they seek approvals to merge\ntheir code, then the approval process for the MR will cause the visibility\nof any unresolved defects and vulnerabilities to come to the attention of\neveryone involved in the approval process. This ensures that oversight\nhappens with just the right timing - not too early and not forgotten. This\nmakes a large-scale contribution to human efficiency in the development\nvalue stream.\n\n- **Advisement** - As much as possible GitLab integrates tools and advice\nright into the feature branch MR context where the defects are visible.\nDevelopers are given full vulnerability details and can take just-in-time\ntraining on specific vulnerabilities. \n\n- **Automated Remediation** - Developers can choose to apply\nauto-remediations when they are available.\n\n- **Collaboration** - They can use MR comments and new issues to collaborate\nwith team mates throughout the organization on resolving defects of all\ntypes.\n\n\nHaving seamless, effortless review environments at a per-feature branch\ngranularity is a critical ingredient in GitLab’s ability to maximize the\nshift left of the above developer capabilities. This is most critical in the\ndeveloper checks that require a running copy of application, which is\nprovided by the review environments. These checks include things such as\nDAST, IAST, API fuzzing and accessibility testing. The industry is also\ncontinuing to multiply the types of defect scanners that require an actively\nrunning copy of the application.\n\n\n## Extending GitLab review environments to other cloud application framework\nPaaS\n\n\nSo you may be thinking, “I love GitLab review environments, but not all of\nour applications are targeting Kubernetes.” It is true that the out-\nof-the-box showcasing of GitLab review environments depends on Kubernetes.\nOne of the key reasons for this is that Kubernetes provides an integrated\ndeclarative deployment capability known as deployment manifests. The\nenvironment isolation capability, known as namespaces, also provides a\ncritical capability. GitLab wires these Kubernetes capabilities up to a few\nkey pieces of GitLab CD to accomplish the magic of isolated, per-feature\nbranch review environments.\n\n\nAs far as I know there is no formal or defacto industry term for what I’ll\ncall “Cloud Application Framework PaaS.” Cloud-provided PaaS can be targeted\nat various “levels” of the problem of building applications. For instance,\nprimitive components such as AWS ELB address the problem of application load\nbalancing by providing a variety of virtual, cloud-scaling and secured\nappliances that you can use as a component of building an application.\nAnother example is [AWS Cognito](https://aws.amazon.com/cognito/) to help\nwith providing user login and profile services to an application build.\n\n\nHowever, there are also cloud PaaS offerings that seek to solve the entire\nproblem of rapid application building and maintenance. These are services\nlike AWS Amplify and AWS AppRunner. These services frequently knit together\nprimitive PaaS components (such as described above) into a composite that\nattempts to accelerate the entire process of building applications.\nFrequently these PaaS also include special CLIs or other developer tools\nthat attempt to abstract the creation, maintenance and deployment of an\nInfrastructure as Code layer. They also tend to be\n[GitOps](/topics/gitops/)-oriented by storing this IaC in the same\nrepository as the application code, which enables full control over\ndeployments via Git controls such as branches and merge requests.\n\n\nThis approach relieves developers of early stage applications from having to\nlearn IaC or hire IaC operations professionals too early. Basically it\nallows avoidance of overly early optimization of onboarding IaC skills. If\nthe application is indeed successful it is quite common to outgrow the\nintegrated IaC support provided by these specialized PaaS, however, the\nevolution is very natural because the managed IaC can simply start to be\ndeveloped by specialists.\n\n\nThe distinction of cloud application framework PaaS is important when\nunderstanding where GitLab can create compound value with Dynamic Review\nEnvironments. I will refer to this kind of PaaS as “Cloud Application\nInfrastructure PaaS” that tries to solve the entire “Building Applications\nProblem.”\n\n\nSo we have a bunch of GitLab interfaces and conventions for implementing\nseamless developer review environments and we have non-Kubernetes cloud\napplication infrastructures that provide declarative deployment interfaces\nand we can indeed make them work together! Interesting it is all done in\nGitLab CI YAML, which means that once you see the art of the possible, you\ncan start implementing dynamic review environment lifecycle management for\nmany custom environment types with the existing GitLab features. \n\n\n## A working, non-Kubernetes example of dynamic review environments in\naction\n\n\n![](https://about.gitlab.com/images/blogimages/environment-friction-lifecycle/CloudFormationDeployAnimatedGif.gif)\n\n\n**Figure 2: Working CD example of review environments for AWS\nCloudFormation**\n\n\nFigure 2 shows the details of an actual non-Kubernetes working example\ncalled CloudFormation AutoDeploy With Dynamic Review Environments. This\nproject enables any AWS CloudFormation template to be deployed. It\nspecifically supports an isolated stack deployment whenever a review branch\nis created and then also destroys that environment when the branch is\nmerged. \n\n\nHere are some of the key design constraints and best practices that allow it\nto support automated review environments.:\n\n\n- **The code is implemented as an include.** Notice that the main\n[.gitlab-ci.yml](https://gitlab.com/guided-explorations/aws/cloudformation-deploy/-/blob/main/.gitlab-ci.yml)\nfiles have only variables applicable to this project and then the inclusion\nof Deploy-AWSCloudFormation.gitlab-ci.yml. This allows you to treat the\nCloudFormation integration as a managed process, shared include to be\nimproved and updated. If the stress of backward compatibility of managing a\nshared dependency is too much, you can encourage developers to make a copy\nof this file to essentially version peg it with their project.\n\n\n- **Avoids Conflict with Auto DevOps CI Stage Names** - The [standard stages\nof Auto Devops are\nhere](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml#L70).\nThis constraint allows the auto deploy template to be leveraged. \n\n\n- **Creates and Sequences Custom Stages as Necessary** - For instance, you\ncan see we’ve added `create-changeset` stage and jobs.\n\n\n- The `deploy-review` job and it’s `environment:` section must have a very\nspecific construction, let’s look at the important details:\n\n  ```\n    rules:\n      - if: '$CI_COMMIT_BRANCH == \"main\"'\n        when: never\n      - if: '$REVIEW_DISABLED'\n        when: never\n      - if: '($CI_COMMIT_TAG || $CI_COMMIT_BRANCH) && $REQUIRE_CHANGESET_APPROVALS == \"true\"'\n        when: manual\n      - if: '($CI_COMMIT_TAG || $CI_COMMIT_BRANCH) && $REQUIRE_CHANGESET_APPROVALS != \"true\"'\n    artifacts:\n      reports:\n        dotenv: envurl.env\n    environment:\n      name: review/$CI_COMMIT_REF_SLUG\n      url: $DYNAMIC_ENVIRONMENT_URL\n      on_stop: stop_review\n  ```\n\n  \n\n  - `rules:` are used to ensure this job only runs when we are not on the main branch. The main branch implements long lived stage and prod environments.\n  - `artifacts:reports:dotenv` allows variables populated during a CI job to become pipeline level variables. The most critical role this does in this job is to allow the URL retrieved from CloudFormation Outputs to be populated into the variable DYNAMIC_ENVIRONMENT_URL. The file `enviurl.env` would have at least the line `DYNAMIC_ENVIRONMENT_URL={url-from-cloudformation}` in it. You can see this in the job code as `echo \"DYNAMIC_ENVIRONMENT_URL=${STACK_ENV_URL}\" >> envurl.env`\n  - `environment:name:` is using the Auto Deploy convention of placing review apps under the review environments top level called `review` The reference $CI_COMMIT_REF_SLUG ensures that the branch (or tag name) is used, but with all illegal characters removed. By your development convention, the Environment Name should become a part of the IaC constructs that ensure both uniqueness as well as identifiability by this pipeline. In GitLab's standard auto deploy for Kubernetes this is done by constructing a namespace that contains the name in this provided parameter. In CloudFormation we make it part of the Stack Name. The value here is exposed in the job as the variable ${ENVRONMENT}.\n  - `environment:url:` it is not self-evident here that the variable DYNAMIC_ENVIRONMENT_URL was populated by the deployment job and added to the file `enviro.env` so that it would contain the right value at this time. This causes the GitLab “Environment” page to have a clickable link to visit the environment. It also is used by DAST and other live application scan engines to find and scan the isolated environment.\n  - `environment:on_stop:` in the deploy-review job is what maps to the `stop_review` named job. This is the magic sauce behind automatic environment deletion when a feature branch is merged. `stop_review` must be written with the correct commands to accomplish the teardown.\n\n## A reusable engineering pattern\n\n\nThis CloudFormation pattern serves as a higher-level pattern of how GitLab\nreview environments can be adopted to any other cloud “Application Level\nPaaS.” This is a term I use to indicate a cloud PaaS that is abstracted\nhighly enough that developers think of it as “a place to deploy\napplications.” Perhaps a good way to contrast it with PaaS that does not\nclaim to serve as an entire application platform. Cloud-based load balancers\nare a good example of a PaaS that performs a utility function for\napplications but is not a place to build an entire cloud application. \n\n\n## Application PaaS for abstracting IaC concerns for developers\n\n\nGitLab auto deploy combines well with the cloud application framework PaaS\nthat has a disposition toward developer productivity by reducing or\neliminating IaC management required by developers. AWS Amplify has such\nproductivity support in the form of a developer specific CLI which allows\nimpacting to be authored and updated in the same Git repository where the\napplication code is stored. Adding an entire scaling database PaaS is as\nsimple as running a single CLI command.\n\n\nGenerally such Application PaaS not only generate and help maintain IaC\nthrough highly abstracted CLI or UI actions, they also contain a single\n`deploy` command which is easily combined with a GitLab Auto Deploy template\nfor working with that particular Application PaaS.\n\n\n## Wrap up\n\n\nHopefully this article has helped you understand that:\n\n\n- GitLab already contains a super valuable feature that automates developer\nenvironment lifecycle management.\n\n- It is critical in addressing a key friction in the DevOps value chain.\n\n- It can be extended beyond Kubernetes to other cloud application framework\nPaaS offerings.\n\n\n\nPhoto by [Sandeep\nSingh](https://unsplash.com/@funjabi?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\non\n[Unsplash](https://unsplash.com/s/photos/friction?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n","engineering",[24,25,26],"DevOps","solutions architecture","AWS",{"slug":28,"featured":6,"template":29},"environment-friction-cycle","BlogPost","content:en-us:blog:environment-friction-cycle.yml","yaml","Environment Friction Cycle","content","en-us/blog/environment-friction-cycle.yml","en-us/blog/environment-friction-cycle","yml",{"_path":38,"_dir":39,"_draft":6,"_partial":6,"_locale":7,"data":40,"_id":461,"_type":31,"title":462,"_source":33,"_file":463,"_stem":464,"_extension":36},"/shared/en-us/main-navigation","en-us",{"logo":41,"freeTrial":46,"sales":51,"login":56,"items":61,"search":392,"minimal":423,"duo":442,"pricingDeployment":451},{"config":42},{"href":43,"dataGaName":44,"dataGaLocation":45},"/","gitlab logo","header",{"text":47,"config":48},"Get free trial",{"href":49,"dataGaName":50,"dataGaLocation":45},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com&glm_content=default-saas-trial/","free trial",{"text":52,"config":53},"Talk to sales",{"href":54,"dataGaName":55,"dataGaLocation":45},"/sales/","sales",{"text":57,"config":58},"Sign in",{"href":59,"dataGaName":60,"dataGaLocation":45},"https://gitlab.com/users/sign_in/","sign in",[62,106,203,208,313,373],{"text":63,"config":64,"cards":66,"footer":89},"Platform",{"dataNavLevelOne":65},"platform",[67,73,81],{"title":63,"description":68,"link":69},"The most comprehensive AI-powered DevSecOps Platform",{"text":70,"config":71},"Explore our Platform",{"href":72,"dataGaName":65,"dataGaLocation":45},"/platform/",{"title":74,"description":75,"link":76},"GitLab Duo (AI)","Build software faster with AI at every stage of development",{"text":77,"config":78},"Meet GitLab Duo",{"href":79,"dataGaName":80,"dataGaLocation":45},"/gitlab-duo/","gitlab duo ai",{"title":82,"description":83,"link":84},"Why GitLab","10 reasons why Enterprises choose GitLab",{"text":85,"config":86},"Learn more",{"href":87,"dataGaName":88,"dataGaLocation":45},"/why-gitlab/","why gitlab",{"title":90,"items":91},"Get started with",[92,97,102],{"text":93,"config":94},"Platform Engineering",{"href":95,"dataGaName":96,"dataGaLocation":45},"/solutions/platform-engineering/","platform engineering",{"text":98,"config":99},"Developer Experience",{"href":100,"dataGaName":101,"dataGaLocation":45},"/developer-experience/","Developer experience",{"text":103,"config":104},"MLOps",{"href":105,"dataGaName":103,"dataGaLocation":45},"/topics/devops/the-role-of-ai-in-devops/",{"text":107,"left":108,"config":109,"link":111,"lists":115,"footer":185},"Product",true,{"dataNavLevelOne":110},"solutions",{"text":112,"config":113},"View all Solutions",{"href":114,"dataGaName":110,"dataGaLocation":45},"/solutions/",[116,141,164],{"title":117,"description":118,"link":119,"items":124},"Automation","CI/CD and automation to accelerate deployment",{"config":120},{"icon":121,"href":122,"dataGaName":123,"dataGaLocation":45},"AutomatedCodeAlt","/solutions/delivery-automation/","automated software delivery",[125,129,133,137],{"text":126,"config":127},"CI/CD",{"href":128,"dataGaLocation":45,"dataGaName":126},"/solutions/continuous-integration/",{"text":130,"config":131},"AI-Assisted Development",{"href":79,"dataGaLocation":45,"dataGaName":132},"AI assisted development",{"text":134,"config":135},"Source Code Management",{"href":136,"dataGaLocation":45,"dataGaName":134},"/solutions/source-code-management/",{"text":138,"config":139},"Automated Software Delivery",{"href":122,"dataGaLocation":45,"dataGaName":140},"Automated software delivery",{"title":142,"description":143,"link":144,"items":149},"Security","Deliver code faster without compromising security",{"config":145},{"href":146,"dataGaName":147,"dataGaLocation":45,"icon":148},"/solutions/application-security-testing/","security and compliance","ShieldCheckLight",[150,154,159],{"text":151,"config":152},"Application Security Testing",{"href":146,"dataGaName":153,"dataGaLocation":45},"Application security testing",{"text":155,"config":156},"Software Supply Chain Security",{"href":157,"dataGaLocation":45,"dataGaName":158},"/solutions/supply-chain/","Software supply chain security",{"text":160,"config":161},"Software Compliance",{"href":162,"dataGaName":163,"dataGaLocation":45},"/solutions/software-compliance/","software compliance",{"title":165,"link":166,"items":171},"Measurement",{"config":167},{"icon":168,"href":169,"dataGaName":170,"dataGaLocation":45},"DigitalTransformation","/solutions/visibility-measurement/","visibility and measurement",[172,176,180],{"text":173,"config":174},"Visibility & Measurement",{"href":169,"dataGaLocation":45,"dataGaName":175},"Visibility and Measurement",{"text":177,"config":178},"Value Stream Management",{"href":179,"dataGaLocation":45,"dataGaName":177},"/solutions/value-stream-management/",{"text":181,"config":182},"Analytics & Insights",{"href":183,"dataGaLocation":45,"dataGaName":184},"/solutions/analytics-and-insights/","Analytics and insights",{"title":186,"items":187},"GitLab for",[188,193,198],{"text":189,"config":190},"Enterprise",{"href":191,"dataGaLocation":45,"dataGaName":192},"/enterprise/","enterprise",{"text":194,"config":195},"Small Business",{"href":196,"dataGaLocation":45,"dataGaName":197},"/small-business/","small business",{"text":199,"config":200},"Public Sector",{"href":201,"dataGaLocation":45,"dataGaName":202},"/solutions/public-sector/","public sector",{"text":204,"config":205},"Pricing",{"href":206,"dataGaName":207,"dataGaLocation":45,"dataNavLevelOne":207},"/pricing/","pricing",{"text":209,"config":210,"link":212,"lists":216,"feature":300},"Resources",{"dataNavLevelOne":211},"resources",{"text":213,"config":214},"View all resources",{"href":215,"dataGaName":211,"dataGaLocation":45},"/resources/",[217,250,272],{"title":218,"items":219},"Getting started",[220,225,230,235,240,245],{"text":221,"config":222},"Install",{"href":223,"dataGaName":224,"dataGaLocation":45},"/install/","install",{"text":226,"config":227},"Quick start guides",{"href":228,"dataGaName":229,"dataGaLocation":45},"/get-started/","quick setup checklists",{"text":231,"config":232},"Learn",{"href":233,"dataGaLocation":45,"dataGaName":234},"https://university.gitlab.com/","learn",{"text":236,"config":237},"Product documentation",{"href":238,"dataGaName":239,"dataGaLocation":45},"https://docs.gitlab.com/","product documentation",{"text":241,"config":242},"Best practice videos",{"href":243,"dataGaName":244,"dataGaLocation":45},"/getting-started-videos/","best practice videos",{"text":246,"config":247},"Integrations",{"href":248,"dataGaName":249,"dataGaLocation":45},"/integrations/","integrations",{"title":251,"items":252},"Discover",[253,258,262,267],{"text":254,"config":255},"Customer success stories",{"href":256,"dataGaName":257,"dataGaLocation":45},"/customers/","customer success stories",{"text":259,"config":260},"Blog",{"href":261,"dataGaName":5,"dataGaLocation":45},"/blog/",{"text":263,"config":264},"Remote",{"href":265,"dataGaName":266,"dataGaLocation":45},"https://handbook.gitlab.com/handbook/company/culture/all-remote/","remote",{"text":268,"config":269},"TeamOps",{"href":270,"dataGaName":271,"dataGaLocation":45},"/teamops/","teamops",{"title":273,"items":274},"Connect",[275,280,285,290,295],{"text":276,"config":277},"GitLab Services",{"href":278,"dataGaName":279,"dataGaLocation":45},"/services/","services",{"text":281,"config":282},"Community",{"href":283,"dataGaName":284,"dataGaLocation":45},"/community/","community",{"text":286,"config":287},"Forum",{"href":288,"dataGaName":289,"dataGaLocation":45},"https://forum.gitlab.com/","forum",{"text":291,"config":292},"Events",{"href":293,"dataGaName":294,"dataGaLocation":45},"/events/","events",{"text":296,"config":297},"Partners",{"href":298,"dataGaName":299,"dataGaLocation":45},"/partners/","partners",{"backgroundColor":301,"textColor":302,"text":303,"image":304,"link":308},"#2f2a6b","#fff","Insights for the future of software development",{"altText":305,"config":306},"the source promo card",{"src":307},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758208064/dzl0dbift9xdizyelkk4.svg",{"text":309,"config":310},"Read the latest",{"href":311,"dataGaName":312,"dataGaLocation":45},"/the-source/","the source",{"text":314,"config":315,"lists":317},"Company",{"dataNavLevelOne":316},"company",[318],{"items":319},[320,325,331,333,338,343,348,353,358,363,368],{"text":321,"config":322},"About",{"href":323,"dataGaName":324,"dataGaLocation":45},"/company/","about",{"text":326,"config":327,"footerGa":330},"Jobs",{"href":328,"dataGaName":329,"dataGaLocation":45},"/jobs/","jobs",{"dataGaName":329},{"text":291,"config":332},{"href":293,"dataGaName":294,"dataGaLocation":45},{"text":334,"config":335},"Leadership",{"href":336,"dataGaName":337,"dataGaLocation":45},"/company/team/e-group/","leadership",{"text":339,"config":340},"Team",{"href":341,"dataGaName":342,"dataGaLocation":45},"/company/team/","team",{"text":344,"config":345},"Handbook",{"href":346,"dataGaName":347,"dataGaLocation":45},"https://handbook.gitlab.com/","handbook",{"text":349,"config":350},"Investor relations",{"href":351,"dataGaName":352,"dataGaLocation":45},"https://ir.gitlab.com/","investor relations",{"text":354,"config":355},"Trust Center",{"href":356,"dataGaName":357,"dataGaLocation":45},"/security/","trust center",{"text":359,"config":360},"AI Transparency Center",{"href":361,"dataGaName":362,"dataGaLocation":45},"/ai-transparency-center/","ai transparency center",{"text":364,"config":365},"Newsletter",{"href":366,"dataGaName":367,"dataGaLocation":45},"/company/contact/","newsletter",{"text":369,"config":370},"Press",{"href":371,"dataGaName":372,"dataGaLocation":45},"/press/","press",{"text":374,"config":375,"lists":376},"Contact us",{"dataNavLevelOne":316},[377],{"items":378},[379,382,387],{"text":52,"config":380},{"href":54,"dataGaName":381,"dataGaLocation":45},"talk to sales",{"text":383,"config":384},"Support portal",{"href":385,"dataGaName":386,"dataGaLocation":45},"https://support.gitlab.com","support portal",{"text":388,"config":389},"Customer portal",{"href":390,"dataGaName":391,"dataGaLocation":45},"https://customers.gitlab.com/customers/sign_in/","customer portal",{"close":393,"login":394,"suggestions":401},"Close",{"text":395,"link":396},"To search repositories and projects, login to",{"text":397,"config":398},"gitlab.com",{"href":59,"dataGaName":399,"dataGaLocation":400},"search login","search",{"text":402,"default":403},"Suggestions",[404,406,410,412,416,420],{"text":74,"config":405},{"href":79,"dataGaName":74,"dataGaLocation":400},{"text":407,"config":408},"Code Suggestions (AI)",{"href":409,"dataGaName":407,"dataGaLocation":400},"/solutions/code-suggestions/",{"text":126,"config":411},{"href":128,"dataGaName":126,"dataGaLocation":400},{"text":413,"config":414},"GitLab on AWS",{"href":415,"dataGaName":413,"dataGaLocation":400},"/partners/technology-partners/aws/",{"text":417,"config":418},"GitLab on Google Cloud",{"href":419,"dataGaName":417,"dataGaLocation":400},"/partners/technology-partners/google-cloud-platform/",{"text":421,"config":422},"Why GitLab?",{"href":87,"dataGaName":421,"dataGaLocation":400},{"freeTrial":424,"mobileIcon":429,"desktopIcon":434,"secondaryButton":437},{"text":425,"config":426},"Start free trial",{"href":427,"dataGaName":50,"dataGaLocation":428},"https://gitlab.com/-/trials/new/","nav",{"altText":430,"config":431},"Gitlab Icon",{"src":432,"dataGaName":433,"dataGaLocation":428},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203874/jypbw1jx72aexsoohd7x.svg","gitlab icon",{"altText":430,"config":435},{"src":436,"dataGaName":433,"dataGaLocation":428},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203875/gs4c8p8opsgvflgkswz9.svg",{"text":438,"config":439},"Get Started",{"href":440,"dataGaName":441,"dataGaLocation":428},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com/compare/gitlab-vs-github/","get started",{"freeTrial":443,"mobileIcon":447,"desktopIcon":449},{"text":444,"config":445},"Learn more about GitLab Duo",{"href":79,"dataGaName":446,"dataGaLocation":428},"gitlab duo",{"altText":430,"config":448},{"src":432,"dataGaName":433,"dataGaLocation":428},{"altText":430,"config":450},{"src":436,"dataGaName":433,"dataGaLocation":428},{"freeTrial":452,"mobileIcon":457,"desktopIcon":459},{"text":453,"config":454},"Back to pricing",{"href":206,"dataGaName":455,"dataGaLocation":428,"icon":456},"back to pricing","GoBack",{"altText":430,"config":458},{"src":432,"dataGaName":433,"dataGaLocation":428},{"altText":430,"config":460},{"src":436,"dataGaName":433,"dataGaLocation":428},"content:shared:en-us:main-navigation.yml","Main Navigation","shared/en-us/main-navigation.yml","shared/en-us/main-navigation",{"_path":466,"_dir":39,"_draft":6,"_partial":6,"_locale":7,"title":467,"button":468,"image":473,"config":477,"_id":479,"_type":31,"_source":33,"_file":480,"_stem":481,"_extension":36},"/shared/en-us/banner","is now in public beta!",{"text":469,"config":470},"Try the Beta",{"href":471,"dataGaName":472,"dataGaLocation":45},"/gitlab-duo/agent-platform/","duo banner",{"altText":474,"config":475},"GitLab Duo Agent Platform",{"src":476},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1753720689/somrf9zaunk0xlt7ne4x.svg",{"layout":478},"release","content:shared:en-us:banner.yml","shared/en-us/banner.yml","shared/en-us/banner",{"_path":483,"_dir":39,"_draft":6,"_partial":6,"_locale":7,"data":484,"_id":722,"_type":31,"title":723,"_source":33,"_file":724,"_stem":725,"_extension":36},"/shared/en-us/main-footer",{"text":485,"source":486,"edit":492,"contribute":497,"config":502,"items":507,"minimal":714},"Git is a trademark of Software Freedom Conservancy and our use of 'GitLab' is under license",{"text":487,"config":488},"View page source",{"href":489,"dataGaName":490,"dataGaLocation":491},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/","page source","footer",{"text":493,"config":494},"Edit this page",{"href":495,"dataGaName":496,"dataGaLocation":491},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/content/","web ide",{"text":498,"config":499},"Please contribute",{"href":500,"dataGaName":501,"dataGaLocation":491},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/CONTRIBUTING.md/","please contribute",{"twitter":503,"facebook":504,"youtube":505,"linkedin":506},"https://twitter.com/gitlab","https://www.facebook.com/gitlab","https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg","https://www.linkedin.com/company/gitlab-com",[508,555,607,651,680],{"title":204,"links":509,"subMenu":524},[510,514,519],{"text":511,"config":512},"View plans",{"href":206,"dataGaName":513,"dataGaLocation":491},"view plans",{"text":515,"config":516},"Why Premium?",{"href":517,"dataGaName":518,"dataGaLocation":491},"/pricing/premium/","why premium",{"text":520,"config":521},"Why Ultimate?",{"href":522,"dataGaName":523,"dataGaLocation":491},"/pricing/ultimate/","why ultimate",[525],{"title":526,"links":527},"Contact Us",[528,531,533,535,540,545,550],{"text":529,"config":530},"Contact sales",{"href":54,"dataGaName":55,"dataGaLocation":491},{"text":383,"config":532},{"href":385,"dataGaName":386,"dataGaLocation":491},{"text":388,"config":534},{"href":390,"dataGaName":391,"dataGaLocation":491},{"text":536,"config":537},"Status",{"href":538,"dataGaName":539,"dataGaLocation":491},"https://status.gitlab.com/","status",{"text":541,"config":542},"Terms of use",{"href":543,"dataGaName":544,"dataGaLocation":491},"/terms/","terms of use",{"text":546,"config":547},"Privacy statement",{"href":548,"dataGaName":549,"dataGaLocation":491},"/privacy/","privacy statement",{"text":551,"config":552},"Cookie preferences",{"dataGaName":553,"dataGaLocation":491,"id":554,"isOneTrustButton":108},"cookie preferences","ot-sdk-btn",{"title":107,"links":556,"subMenu":564},[557,561],{"text":558,"config":559},"DevSecOps platform",{"href":72,"dataGaName":560,"dataGaLocation":491},"devsecops platform",{"text":130,"config":562},{"href":79,"dataGaName":563,"dataGaLocation":491},"ai-assisted development",[565],{"title":566,"links":567},"Topics",[568,573,578,582,587,592,597,602],{"text":569,"config":570},"CICD",{"href":571,"dataGaName":572,"dataGaLocation":491},"/topics/ci-cd/","cicd",{"text":574,"config":575},"GitOps",{"href":576,"dataGaName":577,"dataGaLocation":491},"/topics/gitops/","gitops",{"text":24,"config":579},{"href":580,"dataGaName":581,"dataGaLocation":491},"/topics/devops/","devops",{"text":583,"config":584},"Version Control",{"href":585,"dataGaName":586,"dataGaLocation":491},"/topics/version-control/","version control",{"text":588,"config":589},"DevSecOps",{"href":590,"dataGaName":591,"dataGaLocation":491},"/topics/devsecops/","devsecops",{"text":593,"config":594},"Cloud Native",{"href":595,"dataGaName":596,"dataGaLocation":491},"/topics/cloud-native/","cloud native",{"text":598,"config":599},"AI for Coding",{"href":600,"dataGaName":601,"dataGaLocation":491},"/topics/devops/ai-for-coding/","ai for coding",{"text":603,"config":604},"Agentic AI",{"href":605,"dataGaName":606,"dataGaLocation":491},"/topics/agentic-ai/","agentic ai",{"title":608,"links":609},"Solutions",[610,612,614,619,623,626,630,633,635,638,641,646],{"text":151,"config":611},{"href":146,"dataGaName":151,"dataGaLocation":491},{"text":140,"config":613},{"href":122,"dataGaName":123,"dataGaLocation":491},{"text":615,"config":616},"Agile development",{"href":617,"dataGaName":618,"dataGaLocation":491},"/solutions/agile-delivery/","agile delivery",{"text":620,"config":621},"SCM",{"href":136,"dataGaName":622,"dataGaLocation":491},"source code management",{"text":569,"config":624},{"href":128,"dataGaName":625,"dataGaLocation":491},"continuous integration & delivery",{"text":627,"config":628},"Value stream management",{"href":179,"dataGaName":629,"dataGaLocation":491},"value stream management",{"text":574,"config":631},{"href":632,"dataGaName":577,"dataGaLocation":491},"/solutions/gitops/",{"text":189,"config":634},{"href":191,"dataGaName":192,"dataGaLocation":491},{"text":636,"config":637},"Small business",{"href":196,"dataGaName":197,"dataGaLocation":491},{"text":639,"config":640},"Public sector",{"href":201,"dataGaName":202,"dataGaLocation":491},{"text":642,"config":643},"Education",{"href":644,"dataGaName":645,"dataGaLocation":491},"/solutions/education/","education",{"text":647,"config":648},"Financial services",{"href":649,"dataGaName":650,"dataGaLocation":491},"/solutions/finance/","financial services",{"title":209,"links":652},[653,655,657,659,662,664,666,668,670,672,674,676,678],{"text":221,"config":654},{"href":223,"dataGaName":224,"dataGaLocation":491},{"text":226,"config":656},{"href":228,"dataGaName":229,"dataGaLocation":491},{"text":231,"config":658},{"href":233,"dataGaName":234,"dataGaLocation":491},{"text":236,"config":660},{"href":238,"dataGaName":661,"dataGaLocation":491},"docs",{"text":259,"config":663},{"href":261,"dataGaName":5,"dataGaLocation":491},{"text":254,"config":665},{"href":256,"dataGaName":257,"dataGaLocation":491},{"text":263,"config":667},{"href":265,"dataGaName":266,"dataGaLocation":491},{"text":276,"config":669},{"href":278,"dataGaName":279,"dataGaLocation":491},{"text":268,"config":671},{"href":270,"dataGaName":271,"dataGaLocation":491},{"text":281,"config":673},{"href":283,"dataGaName":284,"dataGaLocation":491},{"text":286,"config":675},{"href":288,"dataGaName":289,"dataGaLocation":491},{"text":291,"config":677},{"href":293,"dataGaName":294,"dataGaLocation":491},{"text":296,"config":679},{"href":298,"dataGaName":299,"dataGaLocation":491},{"title":314,"links":681},[682,684,686,688,690,692,694,698,703,705,707,709],{"text":321,"config":683},{"href":323,"dataGaName":316,"dataGaLocation":491},{"text":326,"config":685},{"href":328,"dataGaName":329,"dataGaLocation":491},{"text":334,"config":687},{"href":336,"dataGaName":337,"dataGaLocation":491},{"text":339,"config":689},{"href":341,"dataGaName":342,"dataGaLocation":491},{"text":344,"config":691},{"href":346,"dataGaName":347,"dataGaLocation":491},{"text":349,"config":693},{"href":351,"dataGaName":352,"dataGaLocation":491},{"text":695,"config":696},"Sustainability",{"href":697,"dataGaName":695,"dataGaLocation":491},"/sustainability/",{"text":699,"config":700},"Diversity, inclusion and belonging (DIB)",{"href":701,"dataGaName":702,"dataGaLocation":491},"/diversity-inclusion-belonging/","Diversity, inclusion and belonging",{"text":354,"config":704},{"href":356,"dataGaName":357,"dataGaLocation":491},{"text":364,"config":706},{"href":366,"dataGaName":367,"dataGaLocation":491},{"text":369,"config":708},{"href":371,"dataGaName":372,"dataGaLocation":491},{"text":710,"config":711},"Modern Slavery Transparency Statement",{"href":712,"dataGaName":713,"dataGaLocation":491},"https://handbook.gitlab.com/handbook/legal/modern-slavery-act-transparency-statement/","modern slavery transparency statement",{"items":715},[716,718,720],{"text":541,"config":717},{"href":543,"dataGaName":544,"dataGaLocation":491},{"text":546,"config":719},{"href":548,"dataGaName":549,"dataGaLocation":491},{"text":551,"config":721},{"dataGaName":553,"dataGaLocation":491,"id":554,"isOneTrustButton":108},"content:shared:en-us:main-footer.yml","Main Footer","shared/en-us/main-footer.yml","shared/en-us/main-footer",[727],{"_path":728,"_dir":729,"_draft":6,"_partial":6,"_locale":7,"content":730,"config":736,"_id":738,"_type":31,"title":19,"_source":33,"_file":739,"_stem":740,"_extension":36},"/en-us/blog/authors/darwin-sanoy","authors",{"role":731,"name":19,"config":732},"Field Chief Cloud Architect",{"headshot":733,"linkedin":734,"ctfId":735},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749659751/Blog/Author%20Headshots/Darwin-Sanoy-headshot-395-square-gitlab-teampage-avatar.png","https://linkedin.com/in/darwinsanoy","DarwinJS",{"template":737},"BlogAuthor","content:en-us:blog:authors:darwin-sanoy.yml","en-us/blog/authors/darwin-sanoy.yml","en-us/blog/authors/darwin-sanoy",{"_path":742,"_dir":39,"_draft":6,"_partial":6,"_locale":7,"header":743,"eyebrow":744,"blurb":745,"button":746,"secondaryButton":750,"_id":752,"_type":31,"title":753,"_source":33,"_file":754,"_stem":755,"_extension":36},"/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":47,"config":747},{"href":748,"dataGaName":50,"dataGaLocation":749},"https://gitlab.com/-/trial_registrations/new?glm_content=default-saas-trial&glm_source=about.gitlab.com/","feature",{"text":52,"config":751},{"href":54,"dataGaName":55,"dataGaLocation":749},"content:shared:en-us:next-steps.yml","Next Steps","shared/en-us/next-steps.yml","shared/en-us/next-steps",{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"seo":757,"content":758,"config":761,"_id":30,"_type":31,"title":32,"_source":33,"_file":34,"_stem":35,"_extension":36},{"title":9,"description":10,"ogTitle":9,"ogDescription":10,"noIndex":6,"ogImage":11,"ogUrl":12,"ogSiteName":13,"ogType":14,"canonicalUrls":12,"schema":15},{"title":17,"description":10,"authors":759,"heroImage":11,"date":20,"body":21,"category":22,"tags":760},[19],[24,25,26],{"slug":28,"featured":6,"template":29},1761814423265]