[{"data":1,"prerenderedAt":1057},["ShallowReactive",2],{"/blog/building-our-web-app-on-gitlab-ci":3,"navigation-en-us":293,"banner-en-us":725,"footer-en-us":735,"blog-post-authors-en-us-Pierre de La Morinerie":996,"blog-related-posts-en-us-building-our-web-app-on-gitlab-ci":1012,"blog-share-wrapper-en-us":1037,"next-steps-en-us":1047},{"id":4,"title":5,"authors":6,"body":8,"category":262,"date":263,"description":264,"extension":265,"externalUrl":266,"faq":266,"featured":267,"heroImage":268,"meta":269,"navigation":283,"path":284,"seo":285,"slug":289,"stem":290,"tags":266,"template":291,"updatedDate":266,"__hash__":292},"blogPosts/en-us/blog/building-our-web-app-on-gitlab-ci.md","Building our web-app on GitLab CI",[7],"Pierre de La Morinerie",{"type":9,"value":10,"toc":251},"minimark",[11,15,18,32,37,45,55,63,66,70,73,76,99,103,106,113,116,120,123,129,133,148,154,161,168,172,179,182,186,189,192,204,214,222],[12,13,14],"p",{},"The railway world is a fast-moving environment. To bring you the latest improvements and fixes as quick as possible, Captain Train’s web-app is often updated, sometimes several times per day.",[12,16,17],{},"Did you always wonder how we manage building and deploying all of this without a jolt? Then read-on: here is a technical peek into our engineering process.",[12,19,20,24,25,31],{},[21,22,23],"strong",{},"Note:"," this post tells the customer story of ",[26,27,30],"a",{"href":28,"rel":29},"https://www.captaintrain.com",[],"Captain Train",".",[33,34,36],"h2",{"id":35},"from-jenkins-to-gitlab-ci","From Jenkins to GitLab CI",[12,38,39,40,44],{},"We used to build our web-app using ",[41,42,43],"span",{},"Jenkins",". A robust and proven solution—which was polling our repositories every minute, and built the appropriate integration and production branches.",[12,46,47,48,51,52,31],{},"However we recently switched to a new system for building our web-app. To host our source-code and perform merge-requests, we’re using a self-managed instance of ",[41,49,50],{},"GitLab",". It’s nice, open-source—and features an integrated build system: ",[41,53,54],{},"GitLab CI",[12,56,57,58,62],{},"See it like Travis, but integrated: just add a custom ",[59,60,61],"code",{},".gitlab-ci.yml"," file at the root of your repository, and GitLab will automatically start building your app in the way you specified.",[12,64,65],{},"Now what’s cool about this?",[33,67,69],{"id":68},"reliable-dockerized-builds","Reliable dockerized builds",[12,71,72],{},"Jenkins builds were all executed on a resource-constrained server—and this made builds slow and unreliable. For instance, we observed several times PhantomJS crashing randomly during tests: apparently it didn’t like several builds running on the same machine at the same time—and a single PhantomJS process crashing would bring all of the others down.",[12,74,75],{},"So the first step of our migration was to insulate builds into Docker containers. In this way:",[77,78,79,86,92],"ul",{},[80,81,82,85],"li",{},[21,83,84],{},"Every build is isolated from the others",", and processes don’t crash each other randomly.",[80,87,88,91],{},[21,89,90],{},"Building the same project on different architectures is easy",", and that’s good news, because we need this to support multiple Debian versions.",[80,93,94,95,98],{},"Project maintainers have ",[21,96,97],{},"greater control on the setup of their build environment",": no need to bother an admin when upgrading an SDK on the shared build machine.",[33,100,102],{"id":101},"it-scales","It scales",[12,104,105],{},"GitLab CI allows us to add more runners very easily. And now that builds are performed in Docker containers, we don’t have to configure the runners specifically with our build tools: any out-of-the-box server will do.",[12,107,108,109,112],{},"Once a new runner is declared, ",[21,110,111],{},"scaling is automatic",": the most available runner will be picked to start every new build. It’s so simple that you can even add your own machine to build locally.",[12,114,115],{},"We’ve already reduced our build time by switching to a more powerful runner—a migration that would have been more difficult to do using Jenkins. Although we regularly optimize the run time of our test suite, sometimes you also need to just throw more CPU at it.",[33,117,119],{"id":118},"easier-to-control","Easier to control",[12,121,122],{},"With Jenkins, the configuration of the build job is stored in an external admin-restricted tool. You need the right credentials to edit the build configuration, and it’s not obvious how to do it.",[12,124,125,126,128],{},"Using GitLab CI, the build jobs are determined solely from the ",[59,127,61],{}," file in the repository. This makes it really simple to edit, and you get all the niceties of your usual git work-flow: versioning, merge requests, and so on. You don’t need to ask permission to add CI to your project. Lowering the barrier to entry for CI is definitely a good thing for engineering quality and developer happiness.",[33,130,132],{"id":131},"tests-on-merge-requests","Tests on merge requests",[12,134,135,136,139,140,144,145,147],{},"GitLab CI makes it really easy to build and test the branch of a ",[21,137,138],{},"merge request"," (or a ",[141,142,143],"em",{},"“Pull request”"," in GitHub slang). Just a few lines added to our ",[59,146,61],{}," file, and we were running tests for every push to a merge request.",[12,149,150,151],{},"![Merge automatically when the build succeeds]",[41,152,153],{},"merge",[12,155,156,157,160],{},"We get nice red-or-green-status, the quite useful ",[141,158,159],{},"“Merge automatically when the build succeeds”"," button — and, as branches are now tested before being merged, much less build breakage.",[12,162,163],{},[164,165],"img",{"alt":166,"src":167},"Build Passed","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398132/blog/Content%20Images/cross-post-gitlab-ci/build-passed.png",[33,169,171],{"id":170},"a-slick-ui","A slick UI",[12,173,174,175,178],{},"GitLab CI provides ",[141,176,177],{},"“Pipelines”",", an overview of all your build jobs. This points you quickly to a failing build, and the stage where the problem occurs. Plus it gets you this warm and fuzzy feeling of safeness when everything is green.",[12,180,181],{},"![Pipelines]",[33,183,185],{"id":184},"in-a-nutshell","In a nutshell",[12,187,188],{},"We found the overall experience quite positive. Once the initial hurdle of making the build pass in a Docker container, integrating it into GitLab CI was really easy. And it gave us tons of positive signals, new features and neat integrations. 10/10, would build again.👍",[12,190,191],{},"Our Android team also migrated their pipeline, and are now building the integration and production Android APK with GitLab CI.",[12,193,194,195,197,198,200,201,31],{},"For further reading, you can find on the official website a nice [overview of GitLab CI features]",[41,196,54],{},", and some [examples of ",[59,199,61],{}," files]",[41,202,203],{},"CI examples",[12,205,206],{},[141,207,208,209,31],{},"This post was originally ",[26,210,213],{"href":211,"rel":212},"https://blog.captaintrain.com/12703-building-on-gitlab-ci",[],"published by Captain Train",[12,215,216],{},[141,217,218,221],{},[26,219,30],{"href":28,"rel":220},[],", the European train ticketing company, makes buying train tickets faster, easier, and ad-free. Their goal is to revolutionize the purchase of train tickets and their doing it by engineering the best user-experience.",[12,223,224,226,227,229,230,232,233,237,232,239,243,246,247],{},[41,225,50],{},":\n",[41,228,54],{},": /solutions/continuous-integration/ ",[41,231,203],{},": ",[26,234,235],{"href":235,"rel":236},"https://docs.gitlab.com/ci/quick_start/",[],[41,238,153],{},[26,240,241],{"href":241,"rel":242},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398132/blog/Content%20Images/cross-post-gitlab-ci/merge-when-build-succeeds.png",[],[41,244,245],{},"pipelines",":",[26,248,249],{"href":249,"rel":250},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1782398133/blog/Content%20Images/cross-post-gitlab-ci/pipelines.png",[],{"title":252,"searchDepth":253,"depth":253,"links":254},"",2,[255,256,257,258,259,260,261],{"id":35,"depth":253,"text":36},{"id":68,"depth":253,"text":69},{"id":101,"depth":253,"text":102},{"id":118,"depth":253,"text":119},{"id":131,"depth":253,"text":132},{"id":170,"depth":253,"text":171},{"id":184,"depth":253,"text":185},"engineering","2016-07-22","5 reasons why Captain Train migrated from Jenkins to GitLab CI","md",null,false,"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749684187/Blog/Hero%20Images/building-our-web-app-on-gitlab-ci-cover.jpg",{"excerpt":270},{"type":9,"value":271},[272,274,276],[12,273,14],{},[12,275,17],{},[12,277,278,24,280,31],{},[21,279,23],{},[26,281,30],{"href":28,"rel":282},[],true,"/en-us/blog/building-our-web-app-on-gitlab-ci",{"title":5,"description":264,"ogTitle":5,"ogDescription":264,"noIndex":267,"ogImage":268,"ogUrl":286,"ogSiteName":287,"ogType":288,"canonicalUrls":286},"https://about.gitlab.com/blog/building-our-web-app-on-gitlab-ci","https://about.gitlab.com","article","building-our-web-app-on-gitlab-ci","en-us/blog/building-our-web-app-on-gitlab-ci","BlogPost","063V7-nRG8zUNiEBKgl9V0fkhCiY_lBUpbrZKimKYOg",{"logo":294,"freeTrial":299,"sales":304,"login":309,"items":314,"search":645,"minimal":676,"duo":695,"switchNav":704,"pricingDeployment":715},{"config":295},{"href":296,"dataGaName":297,"dataGaLocation":298},"/","gitlab logo","header",{"text":300,"config":301},"Get free trial",{"href":302,"dataGaName":303,"dataGaLocation":298},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com&glm_content=default-saas-trial/","free trial",{"text":305,"config":306},"Request a demo",{"href":307,"dataGaName":308,"dataGaLocation":298},"/request-a-demo/","sales",{"text":310,"config":311},"Sign in",{"href":312,"dataGaName":313,"dataGaLocation":298},"https://gitlab.com/users/sign_in/","sign in",[315,401,489,494,569,623],{"text":316,"left":283,"config":317,"menu":319},"Platform",{"dataNavLevelOne":318},"platform",{"type":320,"link":321,"columns":325,"feature":390},"lists",{"text":322,"config":323},"Explore the Platform",{"href":324,"dataGaName":318,"dataGaLocation":298},"/platform/",[326,349,372],{"title":327,"items":328},"Execution & Workflows",[329,334,339,344],{"text":330,"config":331},"CI/CD",{"href":332,"dataGaLocation":298,"dataGaName":333},"/solutions/continuous-integration/","ci/cd",{"text":335,"config":336},"Source Code Management",{"href":337,"dataGaLocation":298,"dataGaName":338},"/solutions/source-code-management/","source code management",{"text":340,"config":341},"Agile Delivery",{"href":342,"dataGaLocation":298,"dataGaName":343},"/solutions/agile-delivery/","agile delivery",{"text":345,"config":346},"Artifact Management",{"href":347,"dataGaLocation":298,"dataGaName":348},"/artifact-central/","artifact management",{"title":350,"items":351},"Security & Governance",[352,357,362,367],{"text":353,"config":354},"Application Security Testing",{"href":355,"dataGaLocation":298,"dataGaName":356},"/solutions/application-security-testing/","application security testing",{"text":358,"config":359},"Governance & Compliance",{"href":360,"dataGaLocation":298,"dataGaName":361},"/solutions/software-compliance/","governance and compliance",{"text":363,"config":364},"Secrets Management",{"href":365,"dataGaLocation":298,"dataGaName":366},"/gitlab-secrets-manager/","secrets management",{"text":368,"config":369},"Supply Chain Security",{"href":370,"dataGaLocation":298,"dataGaName":371},"/solutions/supply-chain/","supply chain security",{"title":373,"items":374},"Context & AI",[375,380,385],{"text":376,"config":377},"Agentic Orchestration",{"href":378,"dataGaLocation":298,"dataGaName":379},"/gitlab-duo-agent-platform/","agentic orchestration",{"text":381,"config":382},"Context Graph",{"href":383,"dataGaLocation":298,"dataGaName":384},"/gitlab-orbit/","context graph",{"text":386,"config":387},"Visibility & Measurement",{"href":388,"dataGaLocation":298,"dataGaName":389},"/solutions/visibility-measurement/","visibility and measurement",{"config":391,"title":394,"text":395,"link":396},{"background":392,"textColor":393},"url('https://res.cloudinary.com/about-gitlab-com/image/upload/v1790185102/o7dn32anqcb6z8dgd3as.jpg')","#000","Why GitLab","One platform for speed with control across your software lifecycle.",{"text":397,"config":398},"Learn more",{"href":399,"dataGaName":400,"dataGaLocation":298},"/why-gitlab/","why gitlab",{"text":402,"left":283,"config":403,"menu":405},"Solutions",{"dataNavLevelOne":404},"solutions",{"type":320,"link":406,"columns":410,"feature":480},{"text":407,"config":408},"View all Solutions",{"href":409,"dataGaName":404,"dataGaLocation":298},"/solutions/",[411,429,447],{"title":412,"items":413},"Outcomes",[414,419,424],{"text":415,"config":416},"DevOps Modernization",{"href":417,"dataGaLocation":298,"dataGaName":418},"/assessments/devops-modernization-assessment/","devops modernization",{"text":420,"config":421},"Security Modernization",{"href":422,"dataGaLocation":298,"dataGaName":423},"/assessments/security-modernization-assessment/","security modernization",{"text":425,"config":426},"AI Modernization",{"href":427,"dataGaLocation":298,"dataGaName":428},"/assessments/ai-modernization-assessment/","ai modernization",{"title":430,"items":431},"By size",[432,437,442],{"text":433,"config":434},"Enterprise",{"href":435,"dataGaLocation":298,"dataGaName":436},"/enterprise/","enterprise",{"text":438,"config":439},"Small Business",{"href":440,"dataGaLocation":298,"dataGaName":441},"/small-business/","small business",{"text":443,"config":444},"Startups",{"href":445,"dataGaLocation":298,"dataGaName":446},"/solutions/startups/","startups",{"title":448,"items":449},"Industries",[450,455,460,465,470,475],{"text":451,"config":452},"Financial Services",{"href":453,"dataGaLocation":298,"dataGaName":454},"/solutions/finance/","financial services",{"text":456,"config":457},"Public Sector",{"href":458,"dataGaLocation":298,"dataGaName":459},"/solutions/public-sector/","public sector",{"text":461,"config":462},"Telecommunications",{"href":463,"dataGaLocation":298,"dataGaName":464},"/solutions/telecommunications/","telecommunications",{"text":466,"config":467},"Automotive",{"href":468,"dataGaLocation":298,"dataGaName":469},"/solutions/automotive/","automotive",{"text":471,"config":472},"Education",{"href":473,"dataGaLocation":298,"dataGaName":474},"/solutions/education/","education",{"text":476,"config":477},"Aerospace",{"href":478,"dataGaLocation":298,"dataGaName":479},"/solutions/aerospace/","aerospace",{"config":481,"title":482,"text":483,"link":484},{"background":392,"textColor":393},"GitLab Security Standard","Learn how to harden your software factory and let AI agents earn autonomy, without trading away security.",{"text":485,"config":486},"Explore the standard",{"href":487,"dataGaName":488,"dataGaLocation":298},"/gitlab-security-standard/","gitlab security standard",{"text":490,"config":491},"Pricing",{"href":492,"dataGaName":493,"dataGaLocation":298,"dataNavLevelOne":493},"/pricing/","pricing",{"text":495,"config":496,"menu":498},"Resources",{"dataNavLevelOne":497},"resources",{"type":320,"link":499,"columns":503,"feature":560},{"text":500,"config":501},"View all resources",{"href":502,"dataGaName":497,"dataGaLocation":298},"/resources/",[504,532],{"title":505,"items":506},"Discover",[507,512,517,522,527],{"text":508,"config":509},"Docs",{"href":510,"dataGaName":511,"dataGaLocation":298},"https://docs.gitlab.com/","docs",{"text":513,"config":514},"University",{"href":515,"dataGaName":516,"dataGaLocation":298},"https://university.gitlab.com/","university",{"text":518,"config":519},"Demo Series",{"href":520,"dataGaName":521,"dataGaLocation":298},"/gitlab-technical-demo-series/","demo series",{"text":523,"config":524},"Demo Hub",{"href":525,"dataGaName":526,"dataGaLocation":298},"/demo-hub/","demo hub",{"text":528,"config":529},"Services",{"href":530,"dataGaName":531,"dataGaLocation":298},"/services/","services",{"title":533,"items":534},"Connect",[535,540,545,550,555],{"text":536,"config":537},"Blog",{"href":538,"dataGaName":539,"dataGaLocation":298},"/blog/","blog",{"text":541,"config":542},"Community",{"href":543,"dataGaName":544,"dataGaLocation":298},"/community/","community",{"text":546,"config":547},"Customers",{"href":548,"dataGaName":549,"dataGaLocation":298},"/customers/","customers",{"text":551,"config":552},"Partners",{"href":553,"dataGaName":554,"dataGaLocation":298},"/partners/","partners",{"text":556,"config":557},"Events",{"href":558,"dataGaName":559,"dataGaLocation":298},"/events/","events",{"config":561,"title":562,"text":563,"link":564},{"background":392,"textColor":393},"What’s new in GitLab","Stay updated with our latest features and improvements.",{"text":565,"config":566},"Read the latest",{"href":567,"dataGaName":568,"dataGaLocation":298},"/whats-new/","whats new",{"text":570,"config":571,"menu":573},"Company",{"dataNavLevelOne":572},"company",{"type":320,"columns":574},[575],{"items":576},[577,582,588,593,598,603,608,613,618],{"text":578,"config":579},"About",{"href":580,"dataGaName":581,"dataGaLocation":298},"/company/","about",{"text":583,"config":584,"footerGa":587},"Jobs",{"href":585,"dataGaName":586,"dataGaLocation":298},"/jobs/","jobs",{"dataGaName":586},{"text":589,"config":590},"Press",{"href":591,"dataGaName":592,"dataGaLocation":298},"/press/","press",{"text":594,"config":595},"Handbook",{"href":596,"dataGaName":597,"dataGaLocation":298},"https://handbook.gitlab.com/","handbook",{"text":599,"config":600},"Leadership",{"href":601,"dataGaName":602,"dataGaLocation":298},"/company/team/e-group/","leadership",{"text":604,"config":605},"Investor relations",{"href":606,"dataGaName":607,"dataGaLocation":298},"https://ir.gitlab.com/overview/default.aspx","investor relations",{"text":609,"config":610},"Trust Center",{"href":611,"dataGaName":612,"dataGaLocation":298},"/security/","trust center",{"text":614,"config":615},"AI Transparency Center",{"href":616,"dataGaName":617,"dataGaLocation":298},"/ai-transparency-center/","ai transparency center",{"text":619,"config":620},"Newsletter",{"href":621,"dataGaName":622,"dataGaLocation":298},"/company/contact/#contact-forms","newsletter",{"text":624,"config":625,"menu":626},"Contact us",{"dataNavLevelOne":572},{"type":320,"columns":627},[628],{"items":629},[630,635,640],{"text":631,"config":632},"Talk to sales",{"href":633,"dataGaName":634,"dataGaLocation":298},"/sales/","talk to sales",{"text":636,"config":637},"Support portal",{"href":638,"dataGaName":639,"dataGaLocation":298},"https://support.gitlab.com/hc/en-us","support portal",{"text":641,"config":642},"Customer portal",{"href":643,"dataGaName":644,"dataGaLocation":298},"https://customers.gitlab.com/customers/sign_in/","customer portal",{"close":646,"login":647,"suggestions":654},"Close",{"text":648,"link":649},"To search repositories and projects, login to",{"text":650,"config":651},"gitlab.com",{"href":312,"dataGaName":652,"dataGaLocation":653},"search login","search",{"text":655,"default":656},"Suggestions",[657,660,663,665,669,673],{"text":658,"config":659},"GitLab Duo Agent Platform",{"href":378,"dataGaName":658,"dataGaLocation":653},{"text":661,"config":662},"Code Suggestions (AI)",{"href":378,"dataGaName":661,"dataGaLocation":653},{"text":330,"config":664},{"href":332,"dataGaName":330,"dataGaLocation":653},{"text":666,"config":667},"GitLab on AWS",{"href":668,"dataGaName":666,"dataGaLocation":653},"/partners/technology-partners/aws/",{"text":670,"config":671},"GitLab on Google Cloud",{"href":672,"dataGaName":670,"dataGaLocation":653},"/partners/technology-partners/google-cloud-platform/",{"text":674,"config":675},"Why GitLab?",{"href":399,"dataGaName":674,"dataGaLocation":653},{"freeTrial":677,"mobileIcon":682,"desktopIcon":687,"secondaryButton":690},{"text":678,"config":679},"Start free trial",{"href":680,"dataGaName":303,"dataGaLocation":681},"https://gitlab.com/-/trials/new/","nav",{"altText":683,"config":684},"Gitlab Icon",{"src":685,"dataGaName":686,"dataGaLocation":681},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203874/jypbw1jx72aexsoohd7x.svg","gitlab icon",{"altText":683,"config":688},{"src":689,"dataGaName":686,"dataGaLocation":681},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203875/gs4c8p8opsgvflgkswz9.svg",{"text":691,"config":692},"Get Started",{"href":693,"dataGaName":694,"dataGaLocation":681},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com/get-started/","get started",{"freeTrial":696,"mobileIcon":700,"desktopIcon":702},{"text":697,"config":698},"Learn more about GitLab Duo",{"href":378,"dataGaName":699,"dataGaLocation":681},"gitlab duo",{"altText":683,"config":701},{"src":685,"dataGaName":686,"dataGaLocation":681},{"altText":683,"config":703},{"src":689,"dataGaName":686,"dataGaLocation":681},{"button":705,"mobileIcon":710,"desktopIcon":712},{"text":706,"config":707},"/switch",{"href":708,"dataGaName":709,"dataGaLocation":681},"#contact","switch",{"altText":683,"config":711},{"src":685,"dataGaName":686,"dataGaLocation":681},{"altText":683,"config":713},{"src":714,"dataGaName":686,"dataGaLocation":681},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1773335277/ohhpiuoxoldryzrnhfrh.png",{"freeTrial":716,"mobileIcon":721,"desktopIcon":723},{"text":717,"config":718},"Back to pricing",{"href":492,"dataGaName":719,"dataGaLocation":681,"icon":720},"back to pricing","GoBack",{"altText":683,"config":722},{"src":685,"dataGaName":686,"dataGaLocation":681},{"altText":683,"config":724},{"src":689,"dataGaName":686,"dataGaLocation":681},{"title":726,"button":727,"config":733},"Ship at agent speed. Prove every step. Transcend is here.",{"text":728,"config":729},"Watch now",{"href":730,"dataGaName":731,"dataGaLocation":732},"/events/transcend/virtual/#watch-gitlab-transcend","transcend-october-2026-banner","global-banner",{"layout":734,"disabled":267},"release",{"data":736},{"text":737,"source":738,"edit":744,"contribute":749,"config":754,"items":759,"minimal":985},"Git is a trademark of Software Freedom Conservancy and our use of 'GitLab' is under license",{"text":739,"config":740},"View page source",{"href":741,"dataGaName":742,"dataGaLocation":743},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/","page source","footer",{"text":745,"config":746},"Edit this page",{"href":747,"dataGaName":748,"dataGaLocation":743},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/content/","web ide",{"text":750,"config":751},"Please contribute",{"href":752,"dataGaName":753,"dataGaLocation":743},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/CONTRIBUTING.md/","please contribute",{"twitter":755,"facebook":756,"youtube":757,"linkedin":758},"https://twitter.com/gitlab","https://www.facebook.com/gitlab","https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg","https://www.linkedin.com/company/gitlab-com",[760,807,865,912,953],{"title":490,"links":761,"subMenu":776},[762,766,771],{"text":763,"config":764},"View plans",{"href":492,"dataGaName":765,"dataGaLocation":743},"view plans",{"text":767,"config":768},"Why Premium?",{"href":769,"dataGaName":770,"dataGaLocation":743},"/pricing/premium/","why premium",{"text":772,"config":773},"Why Ultimate?",{"href":774,"dataGaName":775,"dataGaLocation":743},"/pricing/ultimate/","why ultimate",[777],{"title":778,"links":779},"Contact Us",[780,783,785,787,792,797,802],{"text":781,"config":782},"Contact sales",{"href":633,"dataGaName":308,"dataGaLocation":743},{"text":636,"config":784},{"href":638,"dataGaName":639,"dataGaLocation":743},{"text":641,"config":786},{"href":643,"dataGaName":644,"dataGaLocation":743},{"text":788,"config":789},"Status",{"href":790,"dataGaName":791,"dataGaLocation":743},"https://status.gitlab.com/","status",{"text":793,"config":794},"Terms of use",{"href":795,"dataGaName":796,"dataGaLocation":743},"/terms/","terms of use",{"text":798,"config":799},"Privacy statement",{"href":800,"dataGaName":801,"dataGaLocation":743},"/privacy/","privacy statement",{"text":803,"config":804},"Cookie preferences",{"dataGaName":805,"dataGaLocation":743,"id":806,"isOneTrustButton":283},"cookie preferences","ot-sdk-btn",{"title":316,"links":808,"subMenu":822},[809,812,814,816,818,820],{"text":810,"config":811},"Explore the platform",{"href":324,"dataGaName":318,"dataGaLocation":743},{"text":376,"config":813},{"href":378,"dataGaName":379,"dataGaLocation":743},{"text":330,"config":815},{"href":332,"dataGaName":333,"dataGaLocation":743},{"text":381,"config":817},{"href":383,"dataGaName":384,"dataGaLocation":743},{"text":363,"config":819},{"href":365,"dataGaName":366,"dataGaLocation":743},{"text":394,"config":821},{"href":399,"dataGaName":400,"dataGaLocation":743},[823],{"title":824,"links":825},"Topics",[826,830,835,840,845,850,855,860],{"text":330,"config":827},{"href":828,"dataGaName":829,"dataGaLocation":743},"/topics/ci-cd/","cicd",{"text":831,"config":832},"GitOps",{"href":833,"dataGaName":834,"dataGaLocation":743},"/topics/gitops/","gitops",{"text":836,"config":837},"DevOps",{"href":838,"dataGaName":839,"dataGaLocation":743},"/topics/devops/","devops",{"text":841,"config":842},"Version Control",{"href":843,"dataGaName":844,"dataGaLocation":743},"/topics/version-control/","version control",{"text":846,"config":847},"DevSecOps",{"href":848,"dataGaName":849,"dataGaLocation":743},"/topics/devsecops/","devsecops",{"text":851,"config":852},"Cloud Native",{"href":853,"dataGaName":854,"dataGaLocation":743},"/topics/cloud-native/","cloud native",{"text":856,"config":857},"AI for Coding",{"href":858,"dataGaName":859,"dataGaLocation":743},"/topics/devops/ai-for-coding/","ai for coding",{"text":861,"config":862},"Agentic AI",{"href":863,"dataGaName":864,"dataGaLocation":743},"/topics/agentic-ai/","agentic ai",{"title":402,"links":866},[867,870,873,876,879,882,884,886,888,890,892,895,897,900,904,908],{"text":868,"config":869},"DevOps modernization",{"href":417,"dataGaName":418,"dataGaLocation":743},{"text":871,"config":872},"Security modernization",{"href":422,"dataGaName":423,"dataGaLocation":743},{"text":874,"config":875},"AI modernization",{"href":427,"dataGaName":428,"dataGaLocation":743},{"text":877,"config":878},"Financial services",{"href":453,"dataGaName":454,"dataGaLocation":743},{"text":880,"config":881},"Public sector",{"href":458,"dataGaName":459,"dataGaLocation":743},{"text":461,"config":883},{"href":463,"dataGaName":464,"dataGaLocation":743},{"text":466,"config":885},{"href":468,"dataGaName":469,"dataGaLocation":743},{"text":471,"config":887},{"href":473,"dataGaName":474,"dataGaLocation":743},{"text":476,"config":889},{"href":478,"dataGaName":479,"dataGaLocation":743},{"text":433,"config":891},{"href":435,"dataGaName":436,"dataGaLocation":743},{"text":893,"config":894},"Small business",{"href":440,"dataGaName":441,"dataGaLocation":743},{"text":443,"config":896},{"href":445,"dataGaName":446,"dataGaLocation":743},{"text":831,"config":898},{"href":899,"dataGaName":834,"dataGaLocation":743},"/solutions/gitops/",{"text":901,"config":902},"Software composition analysis",{"href":370,"dataGaName":903,"dataGaLocation":743},"software composition analysis",{"text":905,"config":906},"Value stream management",{"href":388,"dataGaName":907,"dataGaLocation":743},"value stream management",{"text":909,"config":910},"All solutions",{"href":409,"dataGaName":911,"dataGaLocation":743},"all solutions",{"title":495,"links":913},[914,919,924,926,928,930,932,934,936,938,940,942,944,946,949],{"text":915,"config":916},"Install",{"href":917,"dataGaName":918,"dataGaLocation":743},"/install/","install",{"text":920,"config":921},"Quick start guides",{"href":922,"dataGaName":923,"dataGaLocation":743},"/get-started/","quick setup checklists",{"text":508,"config":925},{"href":510,"dataGaName":511,"dataGaLocation":743},{"text":513,"config":927},{"href":515,"dataGaName":516,"dataGaLocation":743},{"text":518,"config":929},{"href":520,"dataGaName":521,"dataGaLocation":743},{"text":523,"config":931},{"href":525,"dataGaName":526,"dataGaLocation":743},{"text":528,"config":933},{"href":530,"dataGaName":531,"dataGaLocation":743},{"text":536,"config":935},{"href":538,"dataGaName":539,"dataGaLocation":743},{"text":541,"config":937},{"href":543,"dataGaName":544,"dataGaLocation":743},{"text":546,"config":939},{"href":548,"dataGaName":549,"dataGaLocation":743},{"text":551,"config":941},{"href":553,"dataGaName":554,"dataGaLocation":743},{"text":556,"config":943},{"href":558,"dataGaName":559,"dataGaLocation":743},{"text":619,"config":945},{"href":621,"dataGaName":622,"dataGaLocation":743},{"text":947,"config":948},"What's new",{"href":567,"dataGaName":568,"dataGaLocation":743},{"text":950,"config":951},"All resources",{"href":502,"dataGaName":952,"dataGaLocation":743},"all resources",{"title":570,"links":954},[955,957,959,961,963,965,967,969,971,975,980],{"text":578,"config":956},{"href":580,"dataGaName":572,"dataGaLocation":743},{"text":583,"config":958},{"href":585,"dataGaName":586,"dataGaLocation":743},{"text":589,"config":960},{"href":591,"dataGaName":592,"dataGaLocation":743},{"text":594,"config":962},{"href":596,"dataGaName":597,"dataGaLocation":743},{"text":599,"config":964},{"href":601,"dataGaName":602,"dataGaLocation":743},{"text":604,"config":966},{"href":606,"dataGaName":607,"dataGaLocation":743},{"text":609,"config":968},{"href":611,"dataGaName":612,"dataGaLocation":743},{"text":614,"config":970},{"href":616,"dataGaName":617,"dataGaLocation":743},{"text":972,"config":973},"Sustainability",{"href":974,"dataGaName":972,"dataGaLocation":743},"/sustainability/",{"text":976,"config":977},"Diversity, inclusion and belonging (DIB)",{"href":978,"dataGaName":979,"dataGaLocation":743},"/diversity-inclusion-belonging/","Diversity, inclusion and belonging",{"text":981,"config":982},"Modern Slavery Transparency Statement",{"href":983,"dataGaName":984,"dataGaLocation":743},"https://handbook.gitlab.com/handbook/legal/modern-slavery-act-transparency-statement/","modern slavery transparency statement",{"items":986},[987,990,993],{"text":988,"config":989},"Terms",{"href":795,"dataGaName":796,"dataGaLocation":743},{"text":991,"config":992},"Cookies",{"dataGaName":805,"dataGaLocation":743,"id":806,"isOneTrustButton":283},{"text":994,"config":995},"Privacy",{"href":800,"dataGaName":801,"dataGaLocation":743},[997],{"id":998,"title":999,"body":266,"config":1000,"content":1002,"description":266,"extension":1006,"meta":1007,"navigation":283,"path":1008,"seo":1009,"stem":1010,"__hash__":1011},"blogAuthors/en-us/blog/authors/pierre-de-la-morinerie.yml","Pierre De La Morinerie",{"template":1001},"BlogAuthor",{"name":7,"config":1003},{"headshot":1004,"ctfId":1005},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749659488/Blog/Author%20Headshots/gitlab-logo-extra-whitespace.png","Pierre-de-La-Morinerie","yml",{},"/en-us/blog/authors/pierre-de-la-morinerie",{},"en-us/blog/authors/pierre-de-la-morinerie","uWaWy-jMCvYqUOQPmFGCMVOouhI8eGHutopv8J4qSg4",[1013,1021,1029],{"title":1014,"description":1015,"heroImage":1016,"category":262,"date":1017,"authors":1018,"slug":1020,"externalUrl":266},"Two front doors: Module-level access in a Django GRC app","A technical deep-dive on restructuring a Django internal tool to support two distinct GitLab teams: Security Compliance and Internal Audit.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097663/Blog/Hero%20Images/Blog/Hero%20Images/Workflow%201800x945_2gQoQIbY9NvjLFpXtsxtXy_1750097663612.png","2026-10-05",[1019],"Donovan Felton","module-level-access-in-a-django-grc-app",{"title":1022,"description":1023,"heroImage":1024,"category":262,"date":1025,"authors":1026,"slug":1028,"externalUrl":266},"How GitLab reduced code-per-agentic-flow ratio by 45%","Learn how Flow Registry, a component-based framework that compiles YAML configurations into fully functional LangGraph flows, helped improve scalability and more.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1774465167/n5hlvrsrheadeccyr1oz.png","2026-09-22",[1027],"Mikolaj Wawrzyniak","how-gitlab-reduced-code-per-agentic-flow-ratio",{"title":1030,"description":1031,"heroImage":1032,"category":262,"date":1033,"authors":1034,"slug":1036,"externalUrl":266},"Co-Create: Building GitLab with our users","How GitLab users collaborated with us to build practical product improvements in the first half of 2026.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1750099203/Blog/Hero%20Images/Blog/Hero%20Images/blog-image-template-1800x945%20%2820%29_2bJGC5ZP3WheoqzlLT05C5_1750099203484.png","2026-09-10",[1035],"Isa Huerga","co-create-h1-2026",{"header":1038,"text":1039,"button":1043,"disclaimer":1046},"Start your free\n\n30-day GitLab trial\n",[1040,1041,1042],"GitLab Duo Agent Platform access","Try our most advanced features","Automate complex tasks with AI",{"text":300,"config":1044},{"href":1045,"dataGaName":303,"dataGaLocation":539},"https://gitlab.com/-/trials/new?glm_content=default-saas-trial&glm_source=about.gitlab.com/blog/","No credit card required.",{"header":1048,"blurb":1049,"button":1050,"secondaryButton":1055},"Start building faster today","See what your team can do with the intelligent orchestration platform for DevSecOps.\n",{"text":1051,"config":1052},"Get your free trial",{"href":1053,"dataGaName":303,"dataGaLocation":1054},"https://gitlab.com/-/trial_registrations/new?glm_content=default-saas-trial&glm_source=about.gitlab.com/","feature",{"text":781,"config":1056},{"href":633,"dataGaName":308,"dataGaLocation":1054},1792010343133]