[{"data":1,"prerenderedAt":1277},["ShallowReactive",2],{"/blog/ios-cicd-with-gitlab":3,"navigation-en-us":491,"banner-en-us":918,"footer-en-us":928,"blog-post-authors-en-us-Darby Frey":1172,"blog-related-posts-en-us-ios-cicd-with-gitlab":1187,"blog-promotions-en-us":1213,"next-steps-en-us":1267},{"id":4,"title":5,"authors":6,"body":8,"category":471,"date":472,"description":473,"extension":474,"externalUrl":475,"faq":475,"featured":476,"heroImage":477,"meta":478,"navigation":125,"path":479,"seo":480,"slug":484,"stem":485,"tags":486,"template":489,"updatedDate":475,"__hash__":490},"blogPosts/en-us/blog/ios-cicd-with-gitlab.md","Tutorial: iOS CI/CD with GitLab",[7],"Darby Frey",{"type":9,"value":10,"toc":455},"minimark",[11,22,31,34,42,47,50,69,79,83,90,94,97,137,140,148,151,155,158,164,177,184,191,195,202,205,211,214,220,224,227,230,251,254,258,261,267,270,276,279,282,288,292,295,301,304,308,315,318,321,338,341,344,347,355,361,370,374,389,392,411,415,418,427,433,436,439,451],[12,13,14,15,21],"p",{},"Creating an automated ",[16,17,20],"a",{"href":18,"rel":19},"https://docs.gitlab.com/ci/",[],"CI/CD"," pipeline for an Apple iOS application can be challenging. Configuring build environments and managing code signing can be very time-consuming and error-prone, and when you get that all working, you still need a way to send your app to Apple.",[12,23,24,25,30],{},"GitLab makes this much easier with ",[16,26,29],{"href":27,"rel":28},"https://docs.gitlab.com/ci/mobile_devops/",[],"GitLab Mobile DevOps",".",[12,32,33],{},"GitLab Mobile DevOps is a collection of features built right into GitLab to solve the biggest challenges mobile teams face in establishing a DevOps practice.",[12,35,36,37,30],{},"In this blog post, I’ll demonstrate how to set up an automated CI/CD pipeline using GitLab and ",[16,38,41],{"href":39,"rel":40},"https://fastlane.tools/",[],"fastlane",[43,44,46],"h2",{"id":45},"prerequisites","Prerequisites",[12,48,49],{},"To get started, there are a few prerequisites you’ll need:",[51,52,53,61],"ul",{},[54,55,56,57],"li",{},"An Apple Developer account - ",[16,58,59],{"href":59,"rel":60},"https://developer.apple.com/",[],[54,62,63,64],{},"Ruby and XCode command line tools installed on your local machine ",[16,65,68],{"href":66,"rel":67},"https://docs.fastlane.tools/getting-started/ios/setup/",[],"https://docs.fastlane.tools/getting-started/ios/setup",[70,71,72],"blockquote",{},[12,73,74,75,30],{},"Try out our ",[16,76,78],{"href":77},"/blog/android-cicd-with-gitlab/","Android CI/CD with GitLab tutorial",[43,80,82],{"id":81},"reference-project","Reference project",[12,84,85,86],{},"For this walkthrough, we’ll use the iOS demo project for reference: ",[16,87,88],{"href":88,"rel":89},"https://gitlab.com/gitlab-org/incubation-engineering/mobile-devops/demo-projects/ios-demo",[],[43,91,93],{"id":92},"install-fastlane","Install fastlane",[12,95,96],{},"If you haven’t done so yet, the first step will be to install fastlane. Do this by creating a file in the root of your project called Gemfile. Give it the following contents:",[98,99,104],"pre",{"className":100,"code":101,"language":102,"meta":103,"style":103},"language-shell shiki shiki-themes github-light","source \"https://rubygems.org\"\n\ngem \"fastlane\"\n","shell","",[105,106,107,120,127],"code",{"__ignoreMap":103},[108,109,112,116],"span",{"class":110,"line":111},"line",1,[108,113,115],{"class":114},"sYu0t","source",[108,117,119],{"class":118},"sYBdl"," \"https://rubygems.org\"\n",[108,121,123],{"class":110,"line":122},2,[108,124,126],{"emptyLinePlaceholder":125},true,"\n",[108,128,130,134],{"class":110,"line":129},3,[108,131,133],{"class":132},"s7eDp","gem",[108,135,136],{"class":118}," \"fastlane\"\n",[12,138,139],{},"Then, from the terminal in your project, run:",[98,141,146],{"className":142,"code":144,"language":145,"meta":103},[143],"language-text","bundle install\n","text",[105,147,144],{"__ignoreMap":103},[12,149,150],{},"This command will install fastlane, and all of its related dependencies.",[43,152,154],{"id":153},"initialize-fastlane","Initialize fastlane",[12,156,157],{},"Now that fastlane is installed, we can set it up for our project. Run the following command from the terminal in your project and choose Option No. 2 since we will be targeting Test Flight in this tutorial:",[98,159,162],{"className":160,"code":161,"language":145,"meta":103},[143],"bundle exec fastlane init\n",[105,163,161],{"__ignoreMap":103},[12,165,166,167,169,170,173,174,30],{},"Running this command will create a new folder in your project called ",[105,168,41],{},". This folder will contain two files ",[105,171,172],{},"Appfile"," and ",[105,175,176],{},"Fastfile",[12,178,179],{},[180,181],"img",{"alt":182,"src":183},"Initialize Fastlane","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782397769/blog/Content%20Images/2023-04-15-ios-cicd-with-gitlab/fastlane-init.png",[12,185,186,187],{},"The Appfile contains the configuration information for the app, and the Fastfile has some sample code that we will replace later. See the fastlane docs for more information about the configuration details in the Appfile ",[16,188,189],{"href":189,"rel":190},"https://docs.fastlane.tools/advanced/Appfile/",[],[43,192,194],{"id":193},"initialize-fastlane-match","Initialize fastlane match",[12,196,197,198],{},"The next step will be to set up fastlane Match, which is the part of fastlane that handles code signing. For more information on fastlane match, see the docs ",[16,199,200],{"href":200,"rel":201},"https://docs.fastlane.tools/actions/match/",[],[12,203,204],{},"We’ll start by running the following command from the terminal in your project:",[98,206,209],{"className":207,"code":208,"language":145,"meta":103},[143],"bundle exec fastlane match init\n",[105,210,208],{"__ignoreMap":103},[12,212,213],{},"This command will prompt you to choose which storage backend you want to use (select gitlab_secure_files) and to input your project path (for example: gitlab-org/gitlab). It will then generate a fastlane Matchfile configured to use your project as the storage backend for fastlane Match.",[12,215,216],{},[180,217],{"alt":218,"src":219},"Initialize fastlane Match","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782397769/blog/Content%20Images/2023-04-15-ios-cicd-with-gitlab/match-init.png",[43,221,223],{"id":222},"generate-a-project-access-token","Generate a project access token",[12,225,226],{},"Next, you'll need a GitLab Access Token to use fastlane Match from your local machine. To create a project access token, visit the Access Tokens section under Settings in your GitLab project. Create a new token with maintainer access to the “api” scope.",[12,228,229],{},"Then run the following command from the terminal in your project replacing “YOUR_NEW_TOKEN” with the access token you just generated:",[98,231,233],{"className":100,"code":232,"language":102,"meta":103,"style":103},"export PRIVATE_TOKEN=YOUR_NEW_TOKEN\n",[105,234,235],{"__ignoreMap":103},[108,236,237,241,245,248],{"class":110,"line":111},[108,238,240],{"class":239},"sD7c4","export",[108,242,244],{"class":243},"sgsFI"," PRIVATE_TOKEN",[108,246,247],{"class":239},"=",[108,249,250],{"class":243},"YOUR_NEW_TOKEN\n",[12,252,253],{},"This will configure fastlane to use this access token when making fastlane Match requests to your project.",[43,255,257],{"id":256},"generate-signing-certificates","Generate signing certificates",[12,259,260],{},"Now that fastlane Match is configured, we can use it to generate the signing certificates and provisioning profiles for our app and upload them to GitLab.",[12,262,263,264,30],{},"NOTE: If you already have these files for your app, see the instructions in this blog post on how to use fastlane to import your existing code signing files ",[16,265,266],{"href":266},"/blog/mobile-devops-with-gitlab-part-3-code-signing-for-ios-with-gitlab-and-fastlane/",[12,268,269],{},"Run the following command from the terminal in your project to generate development code signing files and upload them to GitLab.",[98,271,274],{"className":272,"code":273,"language":145,"meta":103},[143],"bundle exec fastlane match development\n",[105,275,273],{"__ignoreMap":103},[12,277,278],{},"When this command completes, go to the CI/CD settings page in your project and scroll down to the Secure Files section to see the files that were just generated and added to your project.",[12,280,281],{},"While we’re here, we can go ahead and do that same thing for the appstore code signing files. Run the following command to generate the appstore code signing files and upload them to GitLab.",[98,283,286],{"className":284,"code":285,"language":145,"meta":103},[143],"bundle exec fastlane match appstore\n",[105,287,285],{"__ignoreMap":103},[43,289,291],{"id":290},"update-xcode-configuration","Update Xcode configuration",[12,293,294],{},"With the code signing files ready to go, we have one small change to make in Xcode. In your project in Xcode, go to the Signing & Capabilities section and disable automatically managing code signing. Then, select the appropriate provisioning profile and signing certificate from the list based on your build target. The certificates we just generated will show up in that list.",[12,296,297],{},[180,298],{"alt":299,"src":300},"Configure Xcode Provisioning Profiles","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782397769/blog/Content%20Images/2023-04-15-ios-cicd-with-gitlab/xcode.png",[12,302,303],{},"With all of our code signing configuration in place, we can now move on to setting up the integration with the Apple App Store.",[43,305,307],{"id":306},"apple-app-store-integration","Apple App Store integration",[12,309,310,311],{},"The final bit of configuration is the Apple App Store integration. To do this, we’ll need to create an API key in App Store Connect. See the instructions here to create and download the key file to your location machine. This key should have the role of App Manager. ",[16,312,313],{"href":313,"rel":314},"https://developer.apple.com/documentation/appstoreconnectapi/creating_api_keys_for_app_store_connect_api",[],[12,316,317],{},"Once the key is generated, go to Settings, Integrations in your project, and click on the integration for Apple App Store Connect. You’ll be asked to supply the issuer ID and key ID from App Store Connect, along with the key file you just downloaded. With all of that configuration in place, click the Test Settings button to ensure everything works. If it gives you an error, double check your settings and try again. Once it’s working, click Save Changes to save and activate the integration.",[12,319,320],{},"With the integration activated, the following CI variables are added to all pipelines on protected branches and tags:",[51,322,323,328,333],{},[54,324,325],{},[105,326,327],{},"APP_STORE_CONNECT_API_KEY_ISSUER_ID",[54,329,330],{},[105,331,332],{},"APP_STORE_CONNECT_API_KEY_KEY_ID",[54,334,335],{},[105,336,337],{},"APP_STORE_CONNECT_API_KEY_KEY",[12,339,340],{},"These CI variables can be used by fastlane or any custom tooling to interact with the Apple App Store to upload builds, or perform other API enabled tasks.",[43,342,176],{"id":343},"fastfile",[12,345,346],{},"With all of our configuration in place, we can now drop in a sample Fastfile to show how to perform the build, sign, and release actions.",[12,348,349,350,354],{},"From the ",[16,351,353],{"href":88,"rel":352},[],"sample project",", copy the contents of the fastlane/Fastfile and paste it into the Fastfile in your project, replacing the existing content.",[12,356,357],{},[16,358,359],{"href":359,"rel":360},"https://gitlab.com/gitlab-org/incubation-engineering/mobile-devops/demo-projects/ios-demo/-/blob/main/fastlane/Fastfile",[],[12,362,363,364,173,367,30],{},"This sample Fastfile contains two lanes, which are actions fastlane can execute. The lanes in this file are ",[105,365,366],{},"build",[105,368,369],{},"beta",[371,372,373],"h3",{"id":366},"Build",[12,375,376,377,380,381,384,385,388],{},"The build lane will perform just a couple of actions to ",[105,378,379],{},"setup_ci",", ",[105,382,383],{},"match",", and ",[105,386,387],{},"build_app",". This will use the development certificate we generated with fastlane Match earlier to build and sign the app for development.",[371,390,391],{"id":369},"Beta",[12,393,394,395,380,397,380,399,380,402,380,405,384,407,410],{},"The beta lane takes a few more steps to ",[105,396,379],{},[105,398,383],{},[105,400,401],{},"app_store_connect_api_key",[105,403,404],{},"increment_build_number",[105,406,387],{},[105,408,409],{},"upload_to_testflight",". This lane will use the appstore certificates we generated with faslane Match earlier to build and sign the app for an appstore release. This lane also uses the App Store Connect integration to connect to the app store to determine the next build number to use, and to upload the final build to Test Flight.",[371,412,414],{"id":413},"gitlab-ciyml",".gitlab-ci.yml",[12,416,417],{},"With the fastlane configuration ready to go, the last step is to hook it up to GitLab CI.",[12,419,349,420,423,424,426],{},[16,421,353],{"href":88,"rel":422},[],", copy the contents of the ",[105,425,414],{}," file and paste it into the project.",[12,428,429],{},[16,430,431],{"href":431,"rel":432},"https://gitlab.com/gitlab-org/incubation-engineering/mobile-devops/demo-projects/ios-demo/-/blob/main/.gitlab-ci.yml",[],[12,434,435],{},"This is a simplified CI configuration that created two CI jobs to run each of the lanes in fastlane on the GitLab macOS shared runners. The build job will run for all CI pipelines and the beta job will only be run on CI pipelines on the master branch. The beta job is also manually triggered, so you can control when the beta release is pushed to Test Flight.",[12,437,438],{},"With all of this in place, commit all of these changes and push them up to your project. The CI pipeline will kick off, and you can see these jobs in action.",[12,440,441,442,446,447],{},"Cover image by ",[16,443,445],{"href":444},"https://unsplash.com/@john_cameron?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText","John Cameron"," on ",[16,448,450],{"href":449},"https://unsplash.com/photos/DgRb7aAGK4k?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText","Unsplash",[452,453,454],"style",{},"html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}",{"title":103,"searchDepth":122,"depth":122,"links":456},[457,458,459,460,461,462,463,464,465,466],{"id":45,"depth":122,"text":46},{"id":81,"depth":122,"text":82},{"id":92,"depth":122,"text":93},{"id":153,"depth":122,"text":154},{"id":193,"depth":122,"text":194},{"id":222,"depth":122,"text":223},{"id":256,"depth":122,"text":257},{"id":290,"depth":122,"text":291},{"id":306,"depth":122,"text":307},{"id":343,"depth":122,"text":176,"children":467},[468,469,470],{"id":366,"depth":129,"text":373},{"id":369,"depth":129,"text":391},{"id":413,"depth":129,"text":414},"engineering","2023-06-07","Learn how to create an automated CI/CD pipeline using GitLab and fastlane.","md",null,false,"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749669340/Blog/Hero%20Images/john-cameron-DgRb7aAGK4k-unsplash.jpg",{},"/en-us/blog/ios-cicd-with-gitlab",{"title":5,"description":473,"ogTitle":5,"ogDescription":473,"noIndex":476,"ogImage":477,"ogUrl":481,"ogSiteName":482,"ogType":483,"canonicalUrls":481},"https://about.gitlab.com/blog/ios-cicd-with-gitlab","https://about.gitlab.com","article","ios-cicd-with-gitlab","en-us/blog/ios-cicd-with-gitlab",[487,20,488],"DevOps","tutorial","BlogPost","cZER-hDjYaRttbxthHhNlgtuDKVvgA1gjiuIpKPeHaQ",{"logo":492,"freeTrial":497,"sales":502,"login":507,"items":512,"search":838,"minimal":869,"duo":888,"switchNav":897,"pricingDeployment":908},{"config":493},{"href":494,"dataGaName":495,"dataGaLocation":496},"/","gitlab logo","header",{"text":498,"config":499},"Get free trial",{"href":500,"dataGaName":501,"dataGaLocation":496},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com&glm_content=default-saas-trial/","free trial",{"text":503,"config":504},"Request a demo",{"href":505,"dataGaName":506,"dataGaLocation":496},"/sales/?contact-topic=request-demo","sales",{"text":508,"config":509},"Sign in",{"href":510,"dataGaName":511,"dataGaLocation":496},"https://gitlab.com/users/sign_in/","sign in",[513,542,641,646,760,816],{"text":514,"config":515,"menu":517},"Platform",{"dataNavLevelOne":516},"platform",{"type":518,"columns":519},"cards",[520,526,534],{"title":514,"description":521,"link":522},"The intelligent orchestration platform for DevSecOps",{"text":523,"config":524},"Explore our Platform",{"href":525,"dataGaName":516,"dataGaLocation":496},"/platform/",{"title":527,"description":528,"link":529},"GitLab Duo Agent Platform","Agentic AI for the entire software lifecycle",{"text":530,"config":531},"Meet GitLab Duo",{"href":532,"dataGaName":533,"dataGaLocation":496},"/gitlab-duo-agent-platform/","gitlab duo agent platform",{"title":535,"description":536,"link":537},"Why GitLab","See the top reasons enterprises choose GitLab",{"text":538,"config":539},"Learn more",{"href":540,"dataGaName":541,"dataGaLocation":496},"/why-gitlab/","why gitlab",{"text":543,"left":125,"config":544,"menu":546},"Product",{"dataNavLevelOne":545},"solutions",{"type":547,"link":548,"columns":552,"feature":620},"lists",{"text":549,"config":550},"View all Solutions",{"href":551,"dataGaName":545,"dataGaLocation":496},"/solutions/",[553,576,599],{"title":554,"description":555,"link":556,"items":561},"Automation","CI/CD and automation to accelerate deployment",{"config":557},{"icon":558,"href":559,"dataGaName":560,"dataGaLocation":496},"AutomatedCodeAlt","/solutions/delivery-automation/","automated software delivery",[562,565,568,572],{"text":20,"config":563},{"href":564,"dataGaLocation":496,"dataGaName":20},"/solutions/continuous-integration/",{"text":527,"config":566},{"href":532,"dataGaLocation":496,"dataGaName":567},"gitlab duo agent platform - product menu",{"text":569,"config":570},"Source Code Management",{"href":571,"dataGaLocation":496,"dataGaName":569},"/solutions/source-code-management/",{"text":573,"config":574},"Automated Software Delivery",{"href":559,"dataGaLocation":496,"dataGaName":575},"Automated software delivery",{"title":577,"description":578,"link":579,"items":584},"Security","Deliver code faster without compromising security",{"config":580},{"href":581,"dataGaName":582,"dataGaLocation":496,"icon":583},"/solutions/application-security-testing/","security and compliance","ShieldCheckLight",[585,589,594],{"text":586,"config":587},"Application Security Testing",{"href":581,"dataGaName":588,"dataGaLocation":496},"Application security testing",{"text":590,"config":591},"Software Supply Chain Security",{"href":592,"dataGaLocation":496,"dataGaName":593},"/solutions/supply-chain/","Software supply chain security",{"text":595,"config":596},"Software Compliance",{"href":597,"dataGaName":598,"dataGaLocation":496},"/solutions/software-compliance/","software compliance",{"title":600,"link":601,"items":606},"Measurement",{"config":602},{"icon":603,"href":604,"dataGaName":605,"dataGaLocation":496},"DigitalTransformation","/solutions/visibility-measurement/","visibility and measurement",[607,611,615],{"text":608,"config":609},"Visibility & Measurement",{"href":604,"dataGaLocation":496,"dataGaName":610},"Visibility and Measurement",{"text":612,"config":613},"Value Stream Management",{"href":614,"dataGaLocation":496,"dataGaName":612},"/solutions/value-stream-management/",{"text":616,"config":617},"Analytics & Insights",{"href":618,"dataGaLocation":496,"dataGaName":619},"/solutions/analytics-and-insights/","Analytics and insights",{"title":621,"type":547,"items":622},"GitLab for",[623,629,635],{"text":624,"config":625},"Enterprise",{"icon":626,"href":627,"dataGaLocation":496,"dataGaName":628},"Building","/enterprise/","enterprise",{"text":630,"config":631},"Small Business",{"icon":632,"href":633,"dataGaLocation":496,"dataGaName":634},"Work","/small-business/","small business",{"text":636,"config":637},"Public Sector",{"icon":638,"href":639,"dataGaLocation":496,"dataGaName":640},"Organization","/solutions/public-sector/","public sector",{"text":642,"config":643},"Pricing",{"href":644,"dataGaName":645,"dataGaLocation":496,"dataNavLevelOne":645},"/pricing/","pricing",{"text":647,"config":648,"menu":650},"Resources",{"dataNavLevelOne":649},"resources",{"type":547,"link":651,"columns":655,"feature":749},{"text":652,"config":653},"View all resources",{"href":654,"dataGaName":649,"dataGaLocation":496},"/resources/",[656,689,716],{"title":657,"items":658},"Getting started",[659,664,669,674,679,684],{"text":660,"config":661},"Install",{"href":662,"dataGaName":663,"dataGaLocation":496},"/install/","install",{"text":665,"config":666},"Quick start guides",{"href":667,"dataGaName":668,"dataGaLocation":496},"/get-started/","quick setup checklists",{"text":670,"config":671},"Learn",{"href":672,"dataGaLocation":496,"dataGaName":673},"https://university.gitlab.com/","learn",{"text":675,"config":676},"Product documentation",{"href":677,"dataGaName":678,"dataGaLocation":496},"https://docs.gitlab.com/","product documentation",{"text":680,"config":681},"Best practice videos",{"href":682,"dataGaName":683,"dataGaLocation":496},"/getting-started-videos/","best practice videos",{"text":685,"config":686},"Integrations",{"href":687,"dataGaName":688,"dataGaLocation":496},"/integrations/","integrations",{"title":690,"items":691},"Discover",[692,697,702,707,711],{"text":693,"config":694},"Customer success stories",{"href":695,"dataGaName":696,"dataGaLocation":496},"/customers/","customer success stories",{"text":698,"config":699},"Blog",{"href":700,"dataGaName":701,"dataGaLocation":496},"/blog/","blog",{"text":703,"config":704},"Demo Hub",{"href":705,"dataGaName":706,"dataGaLocation":496},"/demo-hub/","demo hub",{"text":708,"config":709},"The Source",{"href":710,"dataGaName":701,"dataGaLocation":496},"/the-source/",{"text":712,"config":713},"Remote",{"href":714,"dataGaName":715,"dataGaLocation":496},"https://handbook.gitlab.com/handbook/company/culture/all-remote/","remote",{"title":717,"items":718},"Connect",[719,724,729,734,739,744],{"text":720,"config":721},"GitLab Services",{"href":722,"dataGaName":723,"dataGaLocation":496},"/services/","services",{"text":725,"config":726},"Contribute",{"href":727,"dataGaName":728,"dataGaLocation":496},"https://contributors.gitlab.com","contribute",{"text":730,"config":731},"Community",{"href":732,"dataGaName":733,"dataGaLocation":496},"/community/","community",{"text":735,"config":736},"Forum",{"href":737,"dataGaName":738,"dataGaLocation":496},"https://forum.gitlab.com/","forum",{"text":740,"config":741},"Events",{"href":742,"dataGaName":743,"dataGaLocation":496},"/events/","events",{"text":745,"config":746},"Partners",{"href":747,"dataGaName":748,"dataGaLocation":496},"/partners/","partners",{"config":750,"title":753,"text":754,"link":755},{"background":751,"textColor":752},"url('https://res.cloudinary.com/about-gitlab-com/image/upload/v1777322348/qpq8yrgn8knii57omj0c.png')","#000","What’s new in GitLab","Stay updated with our latest features and improvements.",{"text":756,"config":757},"Read the latest",{"href":758,"dataGaName":759,"dataGaLocation":496},"/whats-new/","whats new",{"text":761,"config":762,"menu":764},"Company",{"dataNavLevelOne":763},"company",{"type":547,"columns":765},[766],{"items":767},[768,773,779,781,786,791,796,801,806,811],{"text":769,"config":770},"About",{"href":771,"dataGaName":772,"dataGaLocation":496},"/company/","about",{"text":774,"config":775,"footerGa":778},"Jobs",{"href":776,"dataGaName":777,"dataGaLocation":496},"/jobs/","jobs",{"dataGaName":777},{"text":740,"config":780},{"href":742,"dataGaName":743,"dataGaLocation":496},{"text":782,"config":783},"Leadership",{"href":784,"dataGaName":785,"dataGaLocation":496},"/company/team/e-group/","leadership",{"text":787,"config":788},"Handbook",{"href":789,"dataGaName":790,"dataGaLocation":496},"https://handbook.gitlab.com/","handbook",{"text":792,"config":793},"Investor relations",{"href":794,"dataGaName":795,"dataGaLocation":496},"https://ir.gitlab.com/overview/default.aspx","investor relations",{"text":797,"config":798},"Trust Center",{"href":799,"dataGaName":800,"dataGaLocation":496},"/security/","trust center",{"text":802,"config":803},"AI Transparency Center",{"href":804,"dataGaName":805,"dataGaLocation":496},"/ai-transparency-center/","ai transparency center",{"text":807,"config":808},"Newsletter",{"href":809,"dataGaName":810,"dataGaLocation":496},"/company/contact/#contact-forms","newsletter",{"text":812,"config":813},"Press",{"href":814,"dataGaName":815,"dataGaLocation":496},"/press/","press",{"text":817,"config":818,"menu":819},"Contact us",{"dataNavLevelOne":763},{"type":547,"columns":820},[821],{"items":822},[823,828,833],{"text":824,"config":825},"Talk to sales",{"href":826,"dataGaName":827,"dataGaLocation":496},"/sales/","talk to sales",{"text":829,"config":830},"Support portal",{"href":831,"dataGaName":832,"dataGaLocation":496},"https://support.gitlab.com/hc/en-us","support portal",{"text":834,"config":835},"Customer portal",{"href":836,"dataGaName":837,"dataGaLocation":496},"https://customers.gitlab.com/customers/sign_in/","customer portal",{"close":839,"login":840,"suggestions":847},"Close",{"text":841,"link":842},"To search repositories and projects, login to",{"text":843,"config":844},"gitlab.com",{"href":510,"dataGaName":845,"dataGaLocation":846},"search login","search",{"text":848,"default":849},"Suggestions",[850,852,856,858,862,866],{"text":527,"config":851},{"href":532,"dataGaName":527,"dataGaLocation":846},{"text":853,"config":854},"Code Suggestions (AI)",{"href":855,"dataGaName":853,"dataGaLocation":846},"/solutions/code-suggestions/",{"text":20,"config":857},{"href":564,"dataGaName":20,"dataGaLocation":846},{"text":859,"config":860},"GitLab on AWS",{"href":861,"dataGaName":859,"dataGaLocation":846},"/partners/technology-partners/aws/",{"text":863,"config":864},"GitLab on Google Cloud",{"href":865,"dataGaName":863,"dataGaLocation":846},"/partners/technology-partners/google-cloud-platform/",{"text":867,"config":868},"Why GitLab?",{"href":540,"dataGaName":867,"dataGaLocation":846},{"freeTrial":870,"mobileIcon":875,"desktopIcon":880,"secondaryButton":883},{"text":871,"config":872},"Start free trial",{"href":873,"dataGaName":501,"dataGaLocation":874},"https://gitlab.com/-/trials/new/","nav",{"altText":876,"config":877},"Gitlab Icon",{"src":878,"dataGaName":879,"dataGaLocation":874},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203874/jypbw1jx72aexsoohd7x.svg","gitlab icon",{"altText":876,"config":881},{"src":882,"dataGaName":879,"dataGaLocation":874},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203875/gs4c8p8opsgvflgkswz9.svg",{"text":884,"config":885},"Get Started",{"href":886,"dataGaName":887,"dataGaLocation":874},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com/get-started/","get started",{"freeTrial":889,"mobileIcon":893,"desktopIcon":895},{"text":890,"config":891},"Learn more about GitLab Duo",{"href":532,"dataGaName":892,"dataGaLocation":874},"gitlab duo",{"altText":876,"config":894},{"src":878,"dataGaName":879,"dataGaLocation":874},{"altText":876,"config":896},{"src":882,"dataGaName":879,"dataGaLocation":874},{"button":898,"mobileIcon":903,"desktopIcon":905},{"text":899,"config":900},"/switch",{"href":901,"dataGaName":902,"dataGaLocation":874},"#contact","switch",{"altText":876,"config":904},{"src":878,"dataGaName":879,"dataGaLocation":874},{"altText":876,"config":906},{"src":907,"dataGaName":879,"dataGaLocation":874},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1773335277/ohhpiuoxoldryzrnhfrh.png",{"freeTrial":909,"mobileIcon":914,"desktopIcon":916},{"text":910,"config":911},"Back to pricing",{"href":644,"dataGaName":912,"dataGaLocation":874,"icon":913},"back to pricing","GoBack",{"altText":876,"config":915},{"src":878,"dataGaName":879,"dataGaLocation":874},{"altText":876,"config":917},{"src":882,"dataGaName":879,"dataGaLocation":874},{"title":919,"titleMobile":920,"button":921,"config":926},"Duo Agent Platform delivers 400% ROI, per new Forrester Consulting study.","400% ROI: Forrester TEI for GitLab Duo",{"text":538,"config":922},{"href":923,"dataGaName":924,"dataGaLocation":925},"https://about.gitlab.com/blog/gitlab-duo-agent-platform-delivers-400-percent-roi/","forrester-tei-dap-banner","global-banner",{"layout":927,"disabled":476},"release",{"data":929},{"text":930,"source":931,"edit":937,"contribute":942,"config":947,"items":952,"minimal":1161},"Git is a trademark of Software Freedom Conservancy and our use of 'GitLab' is under license",{"text":932,"config":933},"View page source",{"href":934,"dataGaName":935,"dataGaLocation":936},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/","page source","footer",{"text":938,"config":939},"Edit this page",{"href":940,"dataGaName":941,"dataGaLocation":936},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/content/","web ide",{"text":943,"config":944},"Please contribute",{"href":945,"dataGaName":946,"dataGaLocation":936},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/CONTRIBUTING.md/","please contribute",{"twitter":948,"facebook":949,"youtube":950,"linkedin":951},"https://twitter.com/gitlab","https://www.facebook.com/gitlab","https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg","https://www.linkedin.com/company/gitlab-com",[953,1000,1053,1097,1129],{"title":642,"links":954,"subMenu":969},[955,959,964],{"text":956,"config":957},"View plans",{"href":644,"dataGaName":958,"dataGaLocation":936},"view plans",{"text":960,"config":961},"Why Premium?",{"href":962,"dataGaName":963,"dataGaLocation":936},"/pricing/premium/","why premium",{"text":965,"config":966},"Why Ultimate?",{"href":967,"dataGaName":968,"dataGaLocation":936},"/pricing/ultimate/","why ultimate",[970],{"title":971,"links":972},"Contact Us",[973,976,978,980,985,990,995],{"text":974,"config":975},"Contact sales",{"href":826,"dataGaName":506,"dataGaLocation":936},{"text":829,"config":977},{"href":831,"dataGaName":832,"dataGaLocation":936},{"text":834,"config":979},{"href":836,"dataGaName":837,"dataGaLocation":936},{"text":981,"config":982},"Status",{"href":983,"dataGaName":984,"dataGaLocation":936},"https://status.gitlab.com/","status",{"text":986,"config":987},"Terms of use",{"href":988,"dataGaName":989,"dataGaLocation":936},"/terms/","terms of use",{"text":991,"config":992},"Privacy statement",{"href":993,"dataGaName":994,"dataGaLocation":936},"/privacy/","privacy statement",{"text":996,"config":997},"Cookie preferences",{"dataGaName":998,"dataGaLocation":936,"id":999,"isOneTrustButton":125},"cookie preferences","ot-sdk-btn",{"title":543,"links":1001,"subMenu":1010},[1002,1006],{"text":1003,"config":1004},"DevSecOps platform",{"href":525,"dataGaName":1005,"dataGaLocation":936},"devsecops platform",{"text":1007,"config":1008},"AI-Assisted Development",{"href":532,"dataGaName":1009,"dataGaLocation":936},"ai-assisted development",[1011],{"title":1012,"links":1013},"Topics",[1014,1019,1024,1028,1033,1038,1043,1048],{"text":1015,"config":1016},"CICD",{"href":1017,"dataGaName":1018,"dataGaLocation":936},"/topics/ci-cd/","cicd",{"text":1020,"config":1021},"GitOps",{"href":1022,"dataGaName":1023,"dataGaLocation":936},"/topics/gitops/","gitops",{"text":487,"config":1025},{"href":1026,"dataGaName":1027,"dataGaLocation":936},"/topics/devops/","devops",{"text":1029,"config":1030},"Version Control",{"href":1031,"dataGaName":1032,"dataGaLocation":936},"/topics/version-control/","version control",{"text":1034,"config":1035},"DevSecOps",{"href":1036,"dataGaName":1037,"dataGaLocation":936},"/topics/devsecops/","devsecops",{"text":1039,"config":1040},"Cloud Native",{"href":1041,"dataGaName":1042,"dataGaLocation":936},"/topics/cloud-native/","cloud native",{"text":1044,"config":1045},"AI for Coding",{"href":1046,"dataGaName":1047,"dataGaLocation":936},"/topics/devops/ai-for-coding/","ai for coding",{"text":1049,"config":1050},"Agentic AI",{"href":1051,"dataGaName":1052,"dataGaLocation":936},"/topics/agentic-ai/","agentic ai",{"title":1054,"links":1055},"Solutions",[1056,1058,1060,1065,1069,1072,1076,1079,1081,1084,1087,1092],{"text":586,"config":1057},{"href":581,"dataGaName":586,"dataGaLocation":936},{"text":575,"config":1059},{"href":559,"dataGaName":560,"dataGaLocation":936},{"text":1061,"config":1062},"Agile development",{"href":1063,"dataGaName":1064,"dataGaLocation":936},"/solutions/agile-delivery/","agile delivery",{"text":1066,"config":1067},"SCM",{"href":571,"dataGaName":1068,"dataGaLocation":936},"source code management",{"text":1015,"config":1070},{"href":564,"dataGaName":1071,"dataGaLocation":936},"continuous integration & delivery",{"text":1073,"config":1074},"Value stream management",{"href":614,"dataGaName":1075,"dataGaLocation":936},"value stream management",{"text":1020,"config":1077},{"href":1078,"dataGaName":1023,"dataGaLocation":936},"/solutions/gitops/",{"text":624,"config":1080},{"href":627,"dataGaName":628,"dataGaLocation":936},{"text":1082,"config":1083},"Small business",{"href":633,"dataGaName":634,"dataGaLocation":936},{"text":1085,"config":1086},"Public sector",{"href":639,"dataGaName":640,"dataGaLocation":936},{"text":1088,"config":1089},"Education",{"href":1090,"dataGaName":1091,"dataGaLocation":936},"/solutions/education/","education",{"text":1093,"config":1094},"Financial services",{"href":1095,"dataGaName":1096,"dataGaLocation":936},"/solutions/finance/","financial services",{"title":647,"links":1098},[1099,1101,1103,1105,1108,1110,1113,1115,1117,1119,1121,1123,1125,1127],{"text":660,"config":1100},{"href":662,"dataGaName":663,"dataGaLocation":936},{"text":665,"config":1102},{"href":667,"dataGaName":668,"dataGaLocation":936},{"text":670,"config":1104},{"href":672,"dataGaName":673,"dataGaLocation":936},{"text":675,"config":1106},{"href":677,"dataGaName":1107,"dataGaLocation":936},"docs",{"text":698,"config":1109},{"href":700,"dataGaName":701,"dataGaLocation":936},{"text":1111,"config":1112},"What's new",{"href":758,"dataGaName":759,"dataGaLocation":936},{"text":693,"config":1114},{"href":695,"dataGaName":696,"dataGaLocation":936},{"text":712,"config":1116},{"href":714,"dataGaName":715,"dataGaLocation":936},{"text":720,"config":1118},{"href":722,"dataGaName":723,"dataGaLocation":936},{"text":725,"config":1120},{"href":727,"dataGaName":728,"dataGaLocation":936},{"text":730,"config":1122},{"href":732,"dataGaName":733,"dataGaLocation":936},{"text":735,"config":1124},{"href":737,"dataGaName":738,"dataGaLocation":936},{"text":740,"config":1126},{"href":742,"dataGaName":743,"dataGaLocation":936},{"text":745,"config":1128},{"href":747,"dataGaName":748,"dataGaLocation":936},{"title":761,"links":1130},[1131,1133,1135,1137,1139,1141,1145,1150,1152,1154,1156],{"text":769,"config":1132},{"href":771,"dataGaName":763,"dataGaLocation":936},{"text":774,"config":1134},{"href":776,"dataGaName":777,"dataGaLocation":936},{"text":782,"config":1136},{"href":784,"dataGaName":785,"dataGaLocation":936},{"text":787,"config":1138},{"href":789,"dataGaName":790,"dataGaLocation":936},{"text":792,"config":1140},{"href":794,"dataGaName":795,"dataGaLocation":936},{"text":1142,"config":1143},"Sustainability",{"href":1144,"dataGaName":1142,"dataGaLocation":936},"/sustainability/",{"text":1146,"config":1147},"Diversity, inclusion and belonging (DIB)",{"href":1148,"dataGaName":1149,"dataGaLocation":936},"/diversity-inclusion-belonging/","Diversity, inclusion and belonging",{"text":797,"config":1151},{"href":799,"dataGaName":800,"dataGaLocation":936},{"text":807,"config":1153},{"href":809,"dataGaName":810,"dataGaLocation":936},{"text":812,"config":1155},{"href":814,"dataGaName":815,"dataGaLocation":936},{"text":1157,"config":1158},"Modern Slavery Transparency Statement",{"href":1159,"dataGaName":1160,"dataGaLocation":936},"https://handbook.gitlab.com/handbook/legal/modern-slavery-act-transparency-statement/","modern slavery transparency statement",{"items":1162},[1163,1166,1169],{"text":1164,"config":1165},"Terms",{"href":988,"dataGaName":989,"dataGaLocation":936},{"text":1167,"config":1168},"Cookies",{"dataGaName":998,"dataGaLocation":936,"id":999,"isOneTrustButton":125},{"text":1170,"config":1171},"Privacy",{"href":993,"dataGaName":994,"dataGaLocation":936},[1173],{"id":1174,"title":7,"body":475,"config":1175,"content":1177,"description":475,"extension":1181,"meta":1182,"navigation":125,"path":1183,"seo":1184,"stem":1185,"__hash__":1186},"blogAuthors/en-us/blog/authors/darby-frey.yml",{"template":1176},"BlogAuthor",{"name":7,"config":1178},{"headshot":1179,"ctfId":1180},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749668565/Blog/Author%20Headshots/darbyfrey-headshot.png","darbyfrey","yml",{},"/en-us/blog/authors/darby-frey",{},"en-us/blog/authors/darby-frey","lqGN1mYG_LRXzRujnkqXvcZHmVHEKoeXrwJofasmK_8",[1188,1197,1205],{"title":1189,"description":1190,"heroImage":1191,"category":471,"date":1192,"authors":1193,"slug":1196,"externalUrl":475},"Confidential AI for GitLab Self-Hosted","Give developers AI coding agents in GitLab Duo without source code leaving a hardware-encrypted boundary — no GPUs needed.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1773866173/vte9qh8rriznvyclhkes.png","2026-08-06",[1194,1195],"Mathias Ewald","Martin Paloncy, Edgeless Systems","confidential-ai-for-gitlab-self-hosted",{"title":1198,"description":1199,"heroImage":1200,"category":471,"date":1201,"authors":1202,"slug":1204,"externalUrl":475},"Green DevOps: Why carbon measurement belongs in your CI/CD pipeline","CI/CD pipelines have a hidden carbon cost. Here's why measuring it matters, and how you can get started with Eco CI and Carmen in GitLab.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1765809212/noh0mdfn9o94ry9ykura.png","2026-07-09",[1203],"Lysanne Pinto","green-devops-carbon-measurement-cicd-pipeline",{"title":1206,"description":1207,"heroImage":1208,"category":471,"date":1209,"authors":1210,"slug":1212,"externalUrl":475},"How to build CI/CD observability at scale","This practical guide to GitLab pipeline analytics helps self-managed users gain operational insights using Prometheus and Grafana.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1774465167/n5hlvrsrheadeccyr1oz.png","2026-04-28",[1211],"Paul Meresanu","how-to-build-ci-cd-observability-at-scale",{"promotions":1214},[1215,1229,1241,1253],{"id":1216,"categories":1217,"header":1219,"text":1220,"button":1221,"image":1226},"ai-modernization",[1218],"ai","Is AI achieving its promise at scale?","Quiz will take 5 minutes or less",{"text":1222,"config":1223},"Get your AI maturity score",{"href":1224,"dataGaName":1225,"dataGaLocation":701},"/assessments/ai-modernization-assessment/","modernization assessment",{"config":1227},{"src":1228},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/qix0m7kwnd8x2fh1zq49.png",{"id":1230,"categories":1231,"header":1233,"text":1220,"button":1234,"image":1238},"devops-modernization",[1232,1037],"product","Are you just managing tools or shipping innovation?",{"text":1235,"config":1236},"Get your DevOps maturity score",{"href":1237,"dataGaName":1225,"dataGaLocation":701},"/assessments/devops-modernization-assessment/",{"config":1239},{"src":1240},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138785/eg818fmakweyuznttgid.png",{"id":1242,"categories":1243,"header":1245,"text":1220,"button":1246,"image":1250},"security-modernization",[1244],"security","Are you trading speed for security?",{"text":1247,"config":1248},"Get your security maturity score",{"href":1249,"dataGaName":1225,"dataGaLocation":701},"/assessments/security-modernization-assessment/",{"config":1251},{"src":1252},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/p4pbqd9nnjejg5ds6mdk.png",{"id":1254,"paths":1255,"header":1258,"text":1259,"button":1260,"image":1265},"github-azure-migration",[1256,1257],"migration-from-azure-devops-to-gitlab","integrating-azure-devops-scm-and-gitlab","Is your team ready for GitHub's Azure move?","GitHub is already rebuilding around Azure. Find out what it means for you.",{"text":1261,"config":1262},"See how GitLab compares to GitHub",{"href":1263,"dataGaName":1264,"dataGaLocation":701},"/compare/gitlab-vs-github/github-azure-migration/","github azure migration",{"config":1266},{"src":1240},{"header":1268,"blurb":1269,"button":1270,"secondaryButton":1275},"Start building faster today","See what your team can do with the intelligent orchestration platform for DevSecOps.\n",{"text":1271,"config":1272},"Get your free trial",{"href":1273,"dataGaName":501,"dataGaLocation":1274},"https://gitlab.com/-/trial_registrations/new?glm_content=default-saas-trial&glm_source=about.gitlab.com/","feature",{"text":974,"config":1276},{"href":826,"dataGaName":506,"dataGaLocation":1274},1786803752600]