[{"data":1,"prerenderedAt":720},["ShallowReactive",2],{"/en-us/blog/advanced-search-data-migrations/":3,"navigation-en-us":36,"banner-en-us":465,"footer-en-us":482,"Dmitry Gruzd":692,"next-steps-en-us":705},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"seo":8,"content":16,"config":26,"_id":29,"_type":30,"title":31,"_source":32,"_file":33,"_stem":34,"_extension":35},"/en-us/blog/advanced-search-data-migrations","blog",false,"",{"title":9,"description":10,"ogTitle":9,"ogDescription":10,"noIndex":6,"ogImage":11,"ogUrl":12,"ogSiteName":13,"ogType":14,"canonicalUrls":12,"schema":15},"GitLab's data migration process for Advanced Search","We needed a more streamlined data migration process for Advanced search.\nHere's what we did.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749682017/Blog/Hero%20Images/advanced-search-migrations.jpg","https://about.gitlab.com/blog/advanced-search-data-migrations","https://about.gitlab.com","article","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"GitLab's data migration process for Advanced Search\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Dmitry Gruzd\"}],\n        \"datePublished\": \"2021-06-01\",\n      }",{"title":9,"description":10,"authors":17,"heroImage":11,"date":19,"body":20,"category":21,"tags":22},[18],"Dmitry Gruzd","2021-06-01","For some time now, GitLab has been working on enabling the Elasticsearch\n\nintegration on GitLab.com to allow as many GitLab.com users as possible\naccess\n\nto the [Advanced Global\nSearch](https://docs.gitlab.com/ee/user/search/advanced_search.html)\n\nfeatures. Last year, after enabling Advanced Search for all licensed\ncustomers on\n\nGitLab.com we were thinking how to simplify the rollout of some Advanced\nSearch\n\nfeatures that require changing the data in Elasticsearch.\n\n\n(If you're interested in the lessons we learned on our road to Enabling\n\nElasticsearch for GitLab.com, you can read [all about\nit](/blog/elasticsearch-update/).\n\n\n## The data migration process problem \n\n\nSometimes we need to change mappings of an index or backfill a field, and\n\nreindexing everything from scratch or using [Zero downtime\nreindexing](https://docs.gitlab.com/ee/integration/elasticsearch.html#zero-downtime-reindexing)\n\nmight seem like an obvious solution. However, this is not a scalable option\nfor\n\nbig GitLab instances. GitLab.com is the largest known installation of GitLab\nand\n\nas such has a lot of projects, code, issues, merge requests and other things\nthat\n\nneed to be indexed. For example, at the moment our Elasticsearch cluster has\n\nalmost 1 billion documents in it. It would take many weeks or even months to\n\nreindex everything and for all that time indexing would need to remain\npaused, therefore\n\nsearch results would quickly become outdated.\n\n\n## Original plan for multi-version support\n\n\nOriginally, we were planning to introduce multi-version support using an\napproach\n\nthat is fully reliant on GitLab to manage both indices, reading from the old\none\n\nand writing to both until the migration is finished. You can read more\ninformation at\n\n[!18254](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/18254) and\n\n[&1769](https://gitlab.com/groups/gitlab-org/-/epics/1769). As of writing\nthis,\n\nmost of the code for this approach still exists in GitLab in a\nhalf-implemented form.\n\n\nThere were 2 primary concerns with this approach:\n\n\n1. Reindexing would require the GitLab application to read every single\ndocument\n\nfrom the storage and send it to Elasticsearch again. Doing so\n\nwould put a big strain on different parts of the application, such as\ndatabase,\n\nGitaly, and Sidekiq.\n\n1. Reindexing everything from GitLab to the cluster again may be very\nwasteful on\n\noccasions where you only need to change a small part of the index. For\nexample, if\n\nwe want to add epics to the index, it is very wasteful to reindex every\ndocument\n\nin the index when we could very quickly just index all the epics. There are\nmany\n\nsituations where we will be trying to perform some migration that can be\ndone more\n\nefficiently using a targeted approach (e.g. adding a new field to a document\ntype\n\nonly requires reindexing all the documents that actually have that field).\n\n\nFor these reasons we've decided to create a different data migration\nprocess.\n\n\n## Our revised data migration process\n\n\nWe took inspiration from the [Rails DB\nmigrations](https://guides.rubyonrails.org/active_record_migrations.html).\n\nWe wanted to apply the best practices from it without having to re-architect\nwhat\n\nthe Rails team has already implemented.\n\n\nFor example, we've decided that we would have a special directory with\ntime-stamped\n\nmigration files. We wanted to achieve a strict execution order so that many\n\nmigrations might be shipped simultaneously. A special background processing\nworker\n\nwill be checking this folder on schedule. This is slightly different to\nrails background migrations where the operator is required to manually run\nthe migration. We decided to make it fully automated and run it in the\nbackground to avoid the need for self-managed customers to add extra steps\nto the migration process. This would have likely made it much more difficult\nfor everyone involved as there are many ways to run GitLab. This extra\nconstraint also forces us to always think of migrations as possibly\nincomplete at any point in the code which is essential for zero-downtime.\n\n\nAt first, we wanted to store the migration state in the Postgresql database,\nbut\n\ndecided against it since this may not be perfect for the situation where a\nuser\n\nwants to connect a new Elasticsearch cluster to GitLab. It's better to store\nthe\n\nmigrations themselves in the Elasticsearch cluster itself so they're more\nlikely to be in\n\nsync with the data.\n\n\nYou can see your new migration index in your Elasticsearch cluster. It's\ncalled\n\n`gitlab-production-migrations`. GitLab stores a few fields there. We use the\n\nversion number as the document id. This is an example document:\n\n\n```\n\n{\n    \"_id\": \"20210510143200\",\n    \"_source\": {\n        \"completed\": true,\n        \"state\": {\n        },\n        \"started_at\": \"2021-05-12T07:19:08.884Z\",\n        \"completed_at\": \"2021-05-12T07:19:08.884Z\"\n    }\n}\n\n```\n\n\nThe state field is used to store data that's required to run batched\nmigrations.\n\nFor example, for batched migrations we store a slice number and a task id\nfor\n\ncurrent Elasticsearch reindex operation and we update the state after every\nrun.\n\n\nThis is how an example migration looks:\n\n\n```ruby\n\nclass MigrationName \u003C Elastic::Migration\n  def migrate\n    # Migrate the data here\n  end\n\n  def completed?\n    # Return true if completed, otherwise return false\n  end\nend\n\n```\n\n\nThis looks a lot like [Rails DB\nmigrations](https://guides.rubyonrails.org/active_record_migrations.html),\n\nwhich was our goal from the beginning. The main difference is that it has an\nadditional method to\n\ncheck if a migration is completed. We've added that method because we need\nto\n\nexecute asynchronous tasks quite often and we want to check if it's\ncompleted\n\nlater in a different worker process.\n\n\n## Migration framework logic\n\n\nThis is a simple flow chart to demonstrate the high level logic of the new\nmigration framework.\n\n\n```mermaid\n\ngraph TD\n    CRON(cron every 30 minutes) --> |executes| WORKER[MigrationWorker]\n    WORKER --> B(an uncompleted migration is found)\n    B --> HALT(it's halted)\n    B --> UN(it's uncompleted)\n    B --> COMP(it's finished)\n    HALT --> WARN(show warning in the admin UI)\n    WARN --> EX(exit)\n    UN --> PREF(migration preflight checks)\n    PREF --> RUN(execute the migration code)\n    COMP --> MARK(mark it as finished)\n    MARK --> EX\n```\n\n\nAs you can see above, there are multiple different states of a migration.\nFor example,\n\nthe framework allows it to be halted when it has too many failed attempts.\nIn\n\nthat case, the warning will be shown in the admin UI with a button for\nrestarting\n\nthe migration.\n\n\n![How the warning looks\nlike](https://about.gitlab.com/images/blogimages/advanced_search/halted_warning.png)\n\n\n## Configuration options\n\n\nWe've introduced many useful configuration options into the framework, such\nas:\n\n\n- `batched!` - Allows the migration to run in batches. If set, the worker\nwill\n\nre-enqueue itself with a delay which is set using the `throttle_delay`\noption\n\ndescribed below. We use this option to reduce the load and ensure that the\n\nmigration won't time out.\n\n\n- `throttle_delay` - Sets the wait time in between batch runs. This time\nshould be\n\nset high enough to allow each migration batch enough time to finish.\n\n\n- `pause_indexing!` - Pauses indexing while the migration runs. This setting\nwill\n\nrecord the indexing setting before the migration runs and set it back to\nthat\n\nvalue when the migration is completed. GitLab only uses this option when\n\nabsolutely necessary since we attempt to minimize the downtime as much as\npossible.\n\n\n- `space_requirements!` - Verifies that enough free space is available in\nthe\n\ncluster when the migration is running. This setting will halt the migration\nif the\n\nstorage required is not available. This option is used to\n\nprevent situations when your cluster runs out of space when attempting to\nexecute\n\na migration.\n\n\nYou can see the up-to-date list of options in this development\n[documentation\nsection](https://docs.gitlab.com/ee/development/elasticsearch.html#migration-options-supported-by-the-elasticmigrationworker).\n\n\n## Data migration process results\n\n\nWe implemented the Advanced Search migration framework in the 13.6 release\nand\n\nhave been improving it since. You can see some details in the original issue\n\n[#234046](https://gitlab.com/gitlab-org/gitlab/-/issues/234046). The only\n\nrequirement for this new feature is that you should create your index using\nat\n\nleast version 13.0. We have that requirement since we're heavily utilizing\n\naliases, which were introduced in 13.0. As you might know, over the last few\n\nreleases we've been working on separating different document types into\ntheir own\n\nindices. This migration framework has been a tremendous help for our\ninitiative.\n\nWe've already completed the migration of issues (in 13.8), comments (in\n13.11),\n\nand merge requests (in 13.12) with a noticeable performance improvement.\n\n\nSince we've accumulated so many different migrations over the last few\nreleases\n\nand they require us to support multiple code paths for a long period of\ntime,\n\nwe've decided to remove older migrations that were added prior to the 13.12\n\nrelease. You can see some details in this\n[issue](https://gitlab.com/gitlab-org/gitlab/-/issues/329952).\n\nWe plan to continue the same strategy in the future, which is one of the\nreasons\n\nwhy you should always upgrade to the latest minor version before migrating\nto a\n\nmajor release.\n\n\nIf you're interested in contributing to features that require Advanced\nSearch\n\nmigrations, we have a dedicated [documentation\nsection](https://docs.gitlab.com/ee/development/elasticsearch.html#creating-a-new-advanced-search-migration)\n\nthat explains how to create one and lists all available options for it.","engineering",[23,24,25],"features","releases","workflow",{"slug":27,"featured":6,"template":28},"advanced-search-data-migrations","BlogPost","content:en-us:blog:advanced-search-data-migrations.yml","yaml","Advanced Search Data Migrations","content","en-us/blog/advanced-search-data-migrations.yml","en-us/blog/advanced-search-data-migrations","yml",{"_path":37,"_dir":38,"_draft":6,"_partial":6,"_locale":7,"data":39,"_id":461,"_type":30,"title":462,"_source":32,"_file":463,"_stem":464,"_extension":35},"/shared/en-us/main-navigation","en-us",{"logo":40,"freeTrial":45,"sales":50,"login":55,"items":60,"search":392,"minimal":423,"duo":442,"pricingDeployment":451},{"config":41},{"href":42,"dataGaName":43,"dataGaLocation":44},"/","gitlab logo","header",{"text":46,"config":47},"Get free trial",{"href":48,"dataGaName":49,"dataGaLocation":44},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com&glm_content=default-saas-trial/","free trial",{"text":51,"config":52},"Talk to sales",{"href":53,"dataGaName":54,"dataGaLocation":44},"/sales/","sales",{"text":56,"config":57},"Sign in",{"href":58,"dataGaName":59,"dataGaLocation":44},"https://gitlab.com/users/sign_in/","sign in",[61,105,203,208,313,373],{"text":62,"config":63,"cards":65,"footer":88},"Platform",{"dataNavLevelOne":64},"platform",[66,72,80],{"title":62,"description":67,"link":68},"The most comprehensive AI-powered DevSecOps Platform",{"text":69,"config":70},"Explore our Platform",{"href":71,"dataGaName":64,"dataGaLocation":44},"/platform/",{"title":73,"description":74,"link":75},"GitLab Duo (AI)","Build software faster with AI at every stage of development",{"text":76,"config":77},"Meet GitLab Duo",{"href":78,"dataGaName":79,"dataGaLocation":44},"/gitlab-duo/","gitlab duo ai",{"title":81,"description":82,"link":83},"Why GitLab","10 reasons why Enterprises choose GitLab",{"text":84,"config":85},"Learn more",{"href":86,"dataGaName":87,"dataGaLocation":44},"/why-gitlab/","why gitlab",{"title":89,"items":90},"Get started with",[91,96,101],{"text":92,"config":93},"Platform Engineering",{"href":94,"dataGaName":95,"dataGaLocation":44},"/solutions/platform-engineering/","platform engineering",{"text":97,"config":98},"Developer Experience",{"href":99,"dataGaName":100,"dataGaLocation":44},"/developer-experience/","Developer experience",{"text":102,"config":103},"MLOps",{"href":104,"dataGaName":102,"dataGaLocation":44},"/topics/devops/the-role-of-ai-in-devops/",{"text":106,"left":107,"config":108,"link":110,"lists":114,"footer":185},"Product",true,{"dataNavLevelOne":109},"solutions",{"text":111,"config":112},"View all Solutions",{"href":113,"dataGaName":109,"dataGaLocation":44},"/solutions/",[115,140,164],{"title":116,"description":117,"link":118,"items":123},"Automation","CI/CD and automation to accelerate deployment",{"config":119},{"icon":120,"href":121,"dataGaName":122,"dataGaLocation":44},"AutomatedCodeAlt","/solutions/delivery-automation/","automated software delivery",[124,128,132,136],{"text":125,"config":126},"CI/CD",{"href":127,"dataGaLocation":44,"dataGaName":125},"/solutions/continuous-integration/",{"text":129,"config":130},"AI-Assisted Development",{"href":78,"dataGaLocation":44,"dataGaName":131},"AI assisted development",{"text":133,"config":134},"Source Code Management",{"href":135,"dataGaLocation":44,"dataGaName":133},"/solutions/source-code-management/",{"text":137,"config":138},"Automated Software Delivery",{"href":121,"dataGaLocation":44,"dataGaName":139},"Automated software delivery",{"title":141,"description":142,"link":143,"items":148},"Security","Deliver code faster without compromising security",{"config":144},{"href":145,"dataGaName":146,"dataGaLocation":44,"icon":147},"/solutions/security-compliance/","security and compliance","ShieldCheckLight",[149,154,159],{"text":150,"config":151},"Application Security Testing",{"href":152,"dataGaName":153,"dataGaLocation":44},"/solutions/application-security-testing/","Application security testing",{"text":155,"config":156},"Software Supply Chain Security",{"href":157,"dataGaLocation":44,"dataGaName":158},"/solutions/supply-chain/","Software supply chain security",{"text":160,"config":161},"Software Compliance",{"href":162,"dataGaName":163,"dataGaLocation":44},"/solutions/software-compliance/","software compliance",{"title":165,"link":166,"items":171},"Measurement",{"config":167},{"icon":168,"href":169,"dataGaName":170,"dataGaLocation":44},"DigitalTransformation","/solutions/visibility-measurement/","visibility and measurement",[172,176,180],{"text":173,"config":174},"Visibility & Measurement",{"href":169,"dataGaLocation":44,"dataGaName":175},"Visibility and Measurement",{"text":177,"config":178},"Value Stream Management",{"href":179,"dataGaLocation":44,"dataGaName":177},"/solutions/value-stream-management/",{"text":181,"config":182},"Analytics & Insights",{"href":183,"dataGaLocation":44,"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":44,"dataGaName":192},"/enterprise/","enterprise",{"text":194,"config":195},"Small Business",{"href":196,"dataGaLocation":44,"dataGaName":197},"/small-business/","small business",{"text":199,"config":200},"Public Sector",{"href":201,"dataGaLocation":44,"dataGaName":202},"/solutions/public-sector/","public sector",{"text":204,"config":205},"Pricing",{"href":206,"dataGaName":207,"dataGaLocation":44,"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":44},"/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":44},"/install/","install",{"text":226,"config":227},"Quick start guides",{"href":228,"dataGaName":229,"dataGaLocation":44},"/get-started/","quick setup checklists",{"text":231,"config":232},"Learn",{"href":233,"dataGaLocation":44,"dataGaName":234},"https://university.gitlab.com/","learn",{"text":236,"config":237},"Product documentation",{"href":238,"dataGaName":239,"dataGaLocation":44},"https://docs.gitlab.com/","product documentation",{"text":241,"config":242},"Best practice videos",{"href":243,"dataGaName":244,"dataGaLocation":44},"/getting-started-videos/","best practice videos",{"text":246,"config":247},"Integrations",{"href":248,"dataGaName":249,"dataGaLocation":44},"/integrations/","integrations",{"title":251,"items":252},"Discover",[253,258,262,267],{"text":254,"config":255},"Customer success stories",{"href":256,"dataGaName":257,"dataGaLocation":44},"/customers/","customer success stories",{"text":259,"config":260},"Blog",{"href":261,"dataGaName":5,"dataGaLocation":44},"/blog/",{"text":263,"config":264},"Remote",{"href":265,"dataGaName":266,"dataGaLocation":44},"https://handbook.gitlab.com/handbook/company/culture/all-remote/","remote",{"text":268,"config":269},"TeamOps",{"href":270,"dataGaName":271,"dataGaLocation":44},"/teamops/","teamops",{"title":273,"items":274},"Connect",[275,280,285,290,295],{"text":276,"config":277},"GitLab Services",{"href":278,"dataGaName":279,"dataGaLocation":44},"/services/","services",{"text":281,"config":282},"Community",{"href":283,"dataGaName":284,"dataGaLocation":44},"/community/","community",{"text":286,"config":287},"Forum",{"href":288,"dataGaName":289,"dataGaLocation":44},"https://forum.gitlab.com/","forum",{"text":291,"config":292},"Events",{"href":293,"dataGaName":294,"dataGaLocation":44},"/events/","events",{"text":296,"config":297},"Partners",{"href":298,"dataGaName":299,"dataGaLocation":44},"/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":44},"/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":44},"/company/","about",{"text":326,"config":327,"footerGa":330},"Jobs",{"href":328,"dataGaName":329,"dataGaLocation":44},"/jobs/","jobs",{"dataGaName":329},{"text":291,"config":332},{"href":293,"dataGaName":294,"dataGaLocation":44},{"text":334,"config":335},"Leadership",{"href":336,"dataGaName":337,"dataGaLocation":44},"/company/team/e-group/","leadership",{"text":339,"config":340},"Team",{"href":341,"dataGaName":342,"dataGaLocation":44},"/company/team/","team",{"text":344,"config":345},"Handbook",{"href":346,"dataGaName":347,"dataGaLocation":44},"https://handbook.gitlab.com/","handbook",{"text":349,"config":350},"Investor relations",{"href":351,"dataGaName":352,"dataGaLocation":44},"https://ir.gitlab.com/","investor relations",{"text":354,"config":355},"Trust Center",{"href":356,"dataGaName":357,"dataGaLocation":44},"/security/","trust center",{"text":359,"config":360},"AI Transparency Center",{"href":361,"dataGaName":362,"dataGaLocation":44},"/ai-transparency-center/","ai transparency center",{"text":364,"config":365},"Newsletter",{"href":366,"dataGaName":367,"dataGaLocation":44},"/company/contact/","newsletter",{"text":369,"config":370},"Press",{"href":371,"dataGaName":372,"dataGaLocation":44},"/press/","press",{"text":374,"config":375,"lists":376},"Contact us",{"dataNavLevelOne":316},[377],{"items":378},[379,382,387],{"text":51,"config":380},{"href":53,"dataGaName":381,"dataGaLocation":44},"talk to sales",{"text":383,"config":384},"Get help",{"href":385,"dataGaName":386,"dataGaLocation":44},"/support/","get help",{"text":388,"config":389},"Customer portal",{"href":390,"dataGaName":391,"dataGaLocation":44},"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":58,"dataGaName":399,"dataGaLocation":400},"search login","search",{"text":402,"default":403},"Suggestions",[404,406,410,412,416,420],{"text":73,"config":405},{"href":78,"dataGaName":73,"dataGaLocation":400},{"text":407,"config":408},"Code Suggestions (AI)",{"href":409,"dataGaName":407,"dataGaLocation":400},"/solutions/code-suggestions/",{"text":125,"config":411},{"href":127,"dataGaName":125,"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":86,"dataGaName":421,"dataGaLocation":400},{"freeTrial":424,"mobileIcon":429,"desktopIcon":434,"secondaryButton":437},{"text":425,"config":426},"Start free trial",{"href":427,"dataGaName":49,"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":78,"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":38,"_draft":6,"_partial":6,"_locale":7,"title":467,"button":468,"image":473,"config":477,"_id":479,"_type":30,"_source":32,"_file":480,"_stem":481,"_extension":35},"/shared/en-us/banner","is now in public beta!",{"text":469,"config":470},"Try the Beta",{"href":471,"dataGaName":472,"dataGaLocation":44},"/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":38,"_draft":6,"_partial":6,"_locale":7,"data":484,"_id":688,"_type":30,"title":689,"_source":32,"_file":690,"_stem":691,"_extension":35},"/shared/en-us/main-footer",{"text":485,"source":486,"edit":492,"contribute":497,"config":502,"items":507,"minimal":680},"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,531,587,616,650],{"title":62,"links":509,"subMenu":514},[510],{"text":511,"config":512},"DevSecOps platform",{"href":71,"dataGaName":513,"dataGaLocation":491},"devsecops platform",[515],{"title":204,"links":516},[517,521,526],{"text":518,"config":519},"View plans",{"href":206,"dataGaName":520,"dataGaLocation":491},"view plans",{"text":522,"config":523},"Why Premium?",{"href":524,"dataGaName":525,"dataGaLocation":491},"/pricing/premium/","why premium",{"text":527,"config":528},"Why Ultimate?",{"href":529,"dataGaName":530,"dataGaLocation":491},"/pricing/ultimate/","why ultimate",{"title":532,"links":533},"Solutions",[534,539,541,543,548,553,557,560,564,569,571,574,577,582],{"text":535,"config":536},"Digital transformation",{"href":537,"dataGaName":538,"dataGaLocation":491},"/topics/digital-transformation/","digital transformation",{"text":150,"config":540},{"href":152,"dataGaName":150,"dataGaLocation":491},{"text":139,"config":542},{"href":121,"dataGaName":122,"dataGaLocation":491},{"text":544,"config":545},"Agile development",{"href":546,"dataGaName":547,"dataGaLocation":491},"/solutions/agile-delivery/","agile delivery",{"text":549,"config":550},"Cloud transformation",{"href":551,"dataGaName":552,"dataGaLocation":491},"/topics/cloud-native/","cloud transformation",{"text":554,"config":555},"SCM",{"href":135,"dataGaName":556,"dataGaLocation":491},"source code management",{"text":125,"config":558},{"href":127,"dataGaName":559,"dataGaLocation":491},"continuous integration & delivery",{"text":561,"config":562},"Value stream management",{"href":179,"dataGaName":563,"dataGaLocation":491},"value stream management",{"text":565,"config":566},"GitOps",{"href":567,"dataGaName":568,"dataGaLocation":491},"/solutions/gitops/","gitops",{"text":189,"config":570},{"href":191,"dataGaName":192,"dataGaLocation":491},{"text":572,"config":573},"Small business",{"href":196,"dataGaName":197,"dataGaLocation":491},{"text":575,"config":576},"Public sector",{"href":201,"dataGaName":202,"dataGaLocation":491},{"text":578,"config":579},"Education",{"href":580,"dataGaName":581,"dataGaLocation":491},"/solutions/education/","education",{"text":583,"config":584},"Financial services",{"href":585,"dataGaName":586,"dataGaLocation":491},"/solutions/finance/","financial services",{"title":209,"links":588},[589,591,593,595,598,600,602,604,606,608,610,612,614],{"text":221,"config":590},{"href":223,"dataGaName":224,"dataGaLocation":491},{"text":226,"config":592},{"href":228,"dataGaName":229,"dataGaLocation":491},{"text":231,"config":594},{"href":233,"dataGaName":234,"dataGaLocation":491},{"text":236,"config":596},{"href":238,"dataGaName":597,"dataGaLocation":491},"docs",{"text":259,"config":599},{"href":261,"dataGaName":5,"dataGaLocation":491},{"text":254,"config":601},{"href":256,"dataGaName":257,"dataGaLocation":491},{"text":263,"config":603},{"href":265,"dataGaName":266,"dataGaLocation":491},{"text":276,"config":605},{"href":278,"dataGaName":279,"dataGaLocation":491},{"text":268,"config":607},{"href":270,"dataGaName":271,"dataGaLocation":491},{"text":281,"config":609},{"href":283,"dataGaName":284,"dataGaLocation":491},{"text":286,"config":611},{"href":288,"dataGaName":289,"dataGaLocation":491},{"text":291,"config":613},{"href":293,"dataGaName":294,"dataGaLocation":491},{"text":296,"config":615},{"href":298,"dataGaName":299,"dataGaLocation":491},{"title":314,"links":617},[618,620,622,624,626,628,630,634,639,641,643,645],{"text":321,"config":619},{"href":323,"dataGaName":316,"dataGaLocation":491},{"text":326,"config":621},{"href":328,"dataGaName":329,"dataGaLocation":491},{"text":334,"config":623},{"href":336,"dataGaName":337,"dataGaLocation":491},{"text":339,"config":625},{"href":341,"dataGaName":342,"dataGaLocation":491},{"text":344,"config":627},{"href":346,"dataGaName":347,"dataGaLocation":491},{"text":349,"config":629},{"href":351,"dataGaName":352,"dataGaLocation":491},{"text":631,"config":632},"Sustainability",{"href":633,"dataGaName":631,"dataGaLocation":491},"/sustainability/",{"text":635,"config":636},"Diversity, inclusion and belonging (DIB)",{"href":637,"dataGaName":638,"dataGaLocation":491},"/diversity-inclusion-belonging/","Diversity, inclusion and belonging",{"text":354,"config":640},{"href":356,"dataGaName":357,"dataGaLocation":491},{"text":364,"config":642},{"href":366,"dataGaName":367,"dataGaLocation":491},{"text":369,"config":644},{"href":371,"dataGaName":372,"dataGaLocation":491},{"text":646,"config":647},"Modern Slavery Transparency Statement",{"href":648,"dataGaName":649,"dataGaLocation":491},"https://handbook.gitlab.com/handbook/legal/modern-slavery-act-transparency-statement/","modern slavery transparency statement",{"title":651,"links":652},"Contact Us",[653,656,658,660,665,670,675],{"text":654,"config":655},"Contact an expert",{"href":53,"dataGaName":54,"dataGaLocation":491},{"text":383,"config":657},{"href":385,"dataGaName":386,"dataGaLocation":491},{"text":388,"config":659},{"href":390,"dataGaName":391,"dataGaLocation":491},{"text":661,"config":662},"Status",{"href":663,"dataGaName":664,"dataGaLocation":491},"https://status.gitlab.com/","status",{"text":666,"config":667},"Terms of use",{"href":668,"dataGaName":669,"dataGaLocation":491},"/terms/","terms of use",{"text":671,"config":672},"Privacy statement",{"href":673,"dataGaName":674,"dataGaLocation":491},"/privacy/","privacy statement",{"text":676,"config":677},"Cookie preferences",{"dataGaName":678,"dataGaLocation":491,"id":679,"isOneTrustButton":107},"cookie preferences","ot-sdk-btn",{"items":681},[682,684,686],{"text":666,"config":683},{"href":668,"dataGaName":669,"dataGaLocation":491},{"text":671,"config":685},{"href":673,"dataGaName":674,"dataGaLocation":491},{"text":676,"config":687},{"dataGaName":678,"dataGaLocation":491,"id":679,"isOneTrustButton":107},"content:shared:en-us:main-footer.yml","Main Footer","shared/en-us/main-footer.yml","shared/en-us/main-footer",[693],{"_path":694,"_dir":695,"_draft":6,"_partial":6,"_locale":7,"content":696,"config":700,"_id":702,"_type":30,"title":18,"_source":32,"_file":703,"_stem":704,"_extension":35},"/en-us/blog/authors/dmitry-gruzd","authors",{"name":18,"config":697},{"headshot":698,"ctfId":699},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749682014/Blog/Author%20Headshots/dgruzd-headshot.jpg","dgruzd",{"template":701},"BlogAuthor","content:en-us:blog:authors:dmitry-gruzd.yml","en-us/blog/authors/dmitry-gruzd.yml","en-us/blog/authors/dmitry-gruzd",{"_path":706,"_dir":38,"_draft":6,"_partial":6,"_locale":7,"header":707,"eyebrow":708,"blurb":709,"button":710,"secondaryButton":714,"_id":716,"_type":30,"title":717,"_source":32,"_file":718,"_stem":719,"_extension":35},"/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":46,"config":711},{"href":712,"dataGaName":49,"dataGaLocation":713},"https://gitlab.com/-/trial_registrations/new?glm_content=default-saas-trial&glm_source=about.gitlab.com/","feature",{"text":51,"config":715},{"href":53,"dataGaName":54,"dataGaLocation":713},"content:shared:en-us:next-steps.yml","Next Steps","shared/en-us/next-steps.yml","shared/en-us/next-steps",1759347832344]