[{"data":1,"prerenderedAt":706},["ShallowReactive",2],{"/en-us/blog/how-to-bring-devops-to-the-database-with-gitlab-and-liquibase/":3,"navigation-en-us":36,"banner-en-us":452,"footer-en-us":467,"Tsvi Zandany":678,"next-steps-en-us":691},{"_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/how-to-bring-devops-to-the-database-with-gitlab-and-liquibase","blog",false,"",{"title":9,"description":10,"ogTitle":9,"ogDescription":10,"noIndex":6,"ogImage":11,"ogUrl":12,"ogSiteName":13,"ogType":14,"canonicalUrls":12,"schema":15},"How to bring DevOps to the database with GitLab and Liquibase","Learn how to build a continuous delivery pipeline for database code changes with this tutorial.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749672677/Blog/Hero%20Images/metalgears_databasecasestudy.jpg","https://about.gitlab.com/blog/how-to-bring-devops-to-the-database-with-gitlab-and-liquibase","https://about.gitlab.com","article","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How to bring DevOps to the database with GitLab and Liquibase\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Tsvi Zandany\"}],\n        \"datePublished\": \"2022-01-05\",\n      }",{"title":9,"description":10,"authors":17,"heroImage":11,"date":19,"body":20,"category":21,"tags":22},[18],"Tsvi Zandany","2022-01-05","\nIn the [Accelerate State of DevOps 2021 Report](https://cloud.google.com/devops/state-of-devops/), the DevOps Research and Assessment (DORA) team reveals “elite DevOps performers are 3.4 times more likely to exercise database change management compared to their low-performing counterparts.” Tracking changes with version control is not just for application code, though. It’s crucial for managing changes for one of your most important assets: your database.   \n\nThe GitLab DevOps platform enables database management teams to leverage CI/CD to track, manage, and deploy database changes, along with application development and automation and infrastructure as code. Database change management tools have become more advanced in recent years, supporting easier collaboration and communication, which are the keys to successful DevOps. In this blog post, I’ll take you through a tutorial using [Liquibase](https://www.liquibase.com), a tool that integrates seamlessly into the GitLab DevOps platform so your teams can deliver database code changes as fast as application code changes (without compromising on quality and security). \n\n## What is Liquibase?\n\nLiquibase was founded as an open source project over 15 years ago to address getting database changes into version control. With more than 75 million downloads, the company behind Liquibase expanded to paid editions and support to help teams release software faster and safer by bringing the database change process into their existing CI/CD automation.  \n\nIntegrating Liquibase with GitLab CI/CD enables database teams to leverage DevOps automation and best practices for database management. Liquibase helps teams build automated database scripts and gain insights into when, where, and how database changes are deployed. In this tutorial, we’ll demonstrate how to check database scripts for security and compliance issues, speed up database code reviews, perform easy rollbacks, and provide database snapshots to check for malware.\n\n## Adding Liquibase to GitLab’s DevOps Platform\n\nTeams can add Liquibase to GitLab to enable true CI/CD for the database. It’s easy to integrate Liquibase into your GitLab CI/CD pipeline. Before jumping into the tutorial, let’s take a look at the [example Liquibase GitLab project repository](https://gitlab.com/gitlab-com/alliances/liquibase/sandbox-projects/sql_server) you’ll be using.\n\n### Understanding the example Liquibase GitLab project repository\n\n![A CI/CD pipeline diagram](https://about.gitlab.com/images/blogimages/1_CICD_Pipeline_Diagram.png){: .shadow.small.center}\n\nFor this example, the GitLab CI/CD pipeline environments include DEV, QA, and PROD. This pipeline goes through several stages: build, test, deploy, and compare. A post stage comes into play later to capture a snapshot of your database in Production.\n\nStages:\n  - build\n  - test\n  - deploy\n  - compare\n\n### Liquibase commands in the pipeline\n\nFor each of the predefined jobs in the GitLab repository, you’ll be using several Liquibase commands to help manage database changes quickly and safely:\n\n- liquibase_job:\n\n  before_script:\n    - functions\n    - isUpToDate\n    - liquibase checks run\n    - liquibase updateSQL\n    - liquibase update\n    - liquibase rollbackOneUpdate --force\n    - liquibase tag $CI_PIPELINE_ID\n    - liquibase --logFile=${CI_JOB_NAME}_${CI_PIPELINE_ID}.log --logLevel=info update\n    - liquibase history\n\n  script:\n    - echo \"Comparing databases DEV --> QA\"\n    - liquibase diff\n    - liquibase --outputFile=diff_between_DEV_QA.json diff --format=json\n\n  script:\n    - echo \"Snapshotting database PROD\"\n    - liquibase --outputFile=snapshot_PROD.json snapshot --snapshotFormat=json\n\nLearn more about each of these commands in the [README file in the GitLab repository](https://gitlab.com/gitlab-com/alliances/liquibase/sandbox-projects/sql_server/-/blob/main/README.md). \n\n## Tutorial\n\nThe following tutorial demonstrates how to run Liquibase in a GitLab CI/CD pipeline. Follow along by watching this companion video:\n\n\u003C!-- blank line -->\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube.com/embed/ZBFhDayoRYo\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\u003C!-- blank line -->\n\n### Prerequisites\n\nTo start, I’m using a Linux machine with the following:\n\n- [A GitLab account](https://www.gitlab.com)\n- Self-managed Runner on a Linux machine\n- Git\n- Java 11\n- Access to a SQL Server database with multiple environments\n\n### Download, install, and configure Liquibase\n\n[Download Liquibase v4.6.1+](https://www.liquibase.org/download)\n\n[Install Liquibase](https://docs.liquibase.com/concepts/installation/installation-linux-unix-mac.html)\n\n[Get a free Liquibase Pro license key](https://www.liquibase.com/trial). No credit card is required, so you can play with all the advanced features and get support for 30 days. You’ll use this key later when you configure environment variables within GitLab.\n\nEnsure Liquibase is installed properly by running the liquibase --version command. If everything is good you’ll see the following:\n\nStarting Liquibase at 18:10:06 (version 4.6.1 #98 built at 2021-11-04 20:16+0000)\nRunning Java under /usr/lib/jvm/java-11-openjdk-11.0.13.0.8-1.el7_9.x86_64 (Version 11.0.13)\n\nLiquibase Version: 4.6.1\nLiquibase Community 4.6.1 by Liquibase\n\n### Prepare your GitLab project\n\nFork this [example GitLab project repository](https://gitlab.com/gitlab-com/alliances/liquibase/sandbox-projects/sql_server). ([See more information about forking a repository](https://docs.gitlab.com/ee/user/project/repository/forking_workflow.html).)\n\n[Create a self-managed GitLab Runner](https://docs.gitlab.com/runner/) on your Linux instance with your newly forked GitLab project.\n\nClone your newly forked project repository:\ngit clone https://gitlab.com/\u003Cusername>/sql_server.git\n\nGo to the “sql_server” project folder.\ncd sql_server\n\nRun the following command to change your git branch to staging:\ngit checkout staging\n\nConfigure the GitLab CI/CD pipeline environment variables.\n\nYour configuration will include [CI/CD variables](https://docs.gitlab.com/ee/ci/variables/#add-a-cicd-variable-to-a-project), [Liquibase properties](https://www.liquibase.com/blog/secure-database-developer-flow-using-gitlab-pipelines), database credentials, and the Liquibase Pro trial license key so you can use all the advanced Liquibase commands.\n\nFrom the main sql_server project, go to Settings → CI/CD\n\nUnder Variables, click Expand and add the following variables:\n\n![A CI/CD pipeline diagram](https://about.gitlab.com/images/blogimages/liquibasevariables.png){: .shadow.small.center}\n\n![A CI/CD pipeline diagram](https://about.gitlab.com/images/blogimages/liquibasevariables2.png){: .shadow.small.center}\n\n### Configure the self-managed GitLab runner\n\nFrom the main sql_server project, go to Settings → CI/CD\n\nExpand the runners section, click the pencil edit icon, and add the following runner tags (comma separated):\n\ndev_db,prod_db,test_db\n\nNote: Tags are created to help choose which runner will do the job. In this example, we are associating all tags to one runner. Learn more about [configuring runners](https://docs.gitlab.com/ee/ci/runners/configure_runners.html). \n\n### Make changes to the database\n\nEdit the changelog.sql file and add the following changeset after \n\n```\nliquibase formatted sql:\n-- changeset SteveZ:createTable_salesTableZ\nCREATE TABLE salesTableZ (\n   ID int NOT NULL,\n   NAME varchar(20) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,\n   REGION varchar(20) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,\n   MARKET varchar(20) COLLATE SQL_Latin1_General_CP1_CI_AS NULL\n)\n--rollback DROP TABLE salesTableZ\nAdd, commit, and push all new database changes.\ngit add changelog.sql\ngit commit -m “added changelog id and a create table salesTableZ changeset”\ngit push -u origin staging\n```\n\n### Merge the changes and run the pipeline\n\nLet’s merge the changes from branch staging → main to trigger the pipeline to run all jobs.\n\nClick Merge requests → New merge request\n\nSelect staging as Source branch and main as Target branch\n\nClick Compare branches and continue\n\nOn the next screen, click Create merge request\n\nClick Merge to finish merging the changes\n\n![A look at the merge request](https://about.gitlab.com/images/blogimages/2_Merge_Request1.png){: .shadow.small.center}\n\n![Another look at the merge requestt](https://about.gitlab.com/images/blogimages/3_Merge_Request2.png){: .shadow.small.center}\n\nOnce these steps are completed, the code is merged into main and the pipeline is triggered to run.\n\n![The pipeline is triggered](https://about.gitlab.com/images/blogimages/4_Merge_Request3.png){: .shadow.small.center}\n\nTo see the pipeline running, click Pipelines.\n\nTo view the pipeline progress, click the pipeline ID link. You can view each job’s log output by clicking on each job name.\n\n![The pipeline in progress](https://about.gitlab.com/images/blogimages/5_Pipeline_Progress.png){: .shadow.small.center}\n\nClicking into the build-job example:\n\nThe liquibase checks run command validates the SQL for any violations.\n\n```\n57Starting Liquibase at 22:19:14 (version 4.6.1 #98 built at 2021-11-04 20:16+0000)\n58Liquibase Version: 4.6.1\n59Liquibase Pro 4.6.1 by Liquibase licensed to customersuccess until Mon Jun 27 04:59:59 UTC 2022\n60Executing Quality Checks against changelog.sql\n61Executing all checks because a valid Liquibase Pro license was found!\n62Changesets Validated:\n63  ID: createTable_salesTableZ; Author: SteveZ; File path: changelog.sql\n64Checks run against each changeset:\n65  Warn on Detection of 'GRANT' Statements\n66  Warn on Detection of 'REVOKE' Statements\n67  Warn when 'DROP TABLE' detected\n68  Warn when 'DROP COLUMN' detected\n69  Check for specific patterns in sql (Short Name: SqlCreateRoleCheck)\n70  Warn when 'TRUNCATE TABLE' detected\n71  Warn on Detection of grant that contains 'WITH ADMIN OPTION'\n72Liquibase command 'checks run' was executed successfully.\n```\n\nThe liquibase update command deploys the changes. If you choose, you can view a full report of your changes in [Liquibase Hub](https://docs.liquibase.com/tools-integrations/liquibase-hub/setup.html). The update command also saves the deployment log output file as an artifact.\n\n```\n227Starting Liquibase at 22:19:34 (version 4.6.1 #98 built at 2021-11-04 20:16+0000)\n228Liquibase Version: 4.6.1\n229Liquibase Pro 4.6.1 by Liquibase licensed to customersuccess until Mon Jun 27 04:59:59 UTC 2022\n230----------------------------------------------------------------------\n231View a report of this operation at https://hub.liquibase.com/r/I7ens13ooM\n232* IMPORTANT: New users of Hub first need to Sign In to your account\n233with the one-time password sent to your email, which also serves as\n234your username.\n235----------------------------------------------------------------------\n236Logs saved to /home/gitlab-runner/builds/3-UvD4aX/0/szandany/sql_server/build-job_405710044.log\n237Liquibase command 'update' was executed successfully.\n```\n\nHere’s what your Liquibase Hub report will look like:\n\n![The hub report, part one](https://about.gitlab.com/images/blogimages/6_LiquibaseHub_Report.png){: .shadow.small.center}\n\n![The hub report, part twot](https://about.gitlab.com/images/blogimages/7_LiquibaseHub_Report.png){: .shadow.small.center}\n\nThe Liquibase history command will show what changes are currently in the database.\n\n```\n255Starting Liquibase at 22:19:40 (version 4.6.1 #98 built at 2021-11-04 20:16+0000)\n256Liquibase Version: 4.6.1\n257Liquibase Pro 4.6.1 by Liquibase licensed to customersuccess until Mon Jun 27 04:59:59 UTC 2022\n258Liquibase History for jdbc:sqlserver://localhost:1433;sendTemporalDataTypesAsStringForBulkCopy=true;delayLoadingLobs=true;useFmtOnly=false;useBulkCopyForBatchInsert=false;cancelQueryTimeout=-1;sslProtocol=TLS;jaasConfigurationName=SQLJDBCDriver;statementPoolingCacheSize=0;serverPreparedStatementDiscardThreshold=10;enablePrepareOnFirstPreparedStatementCall=false;fips=false;socketTimeout=0;authentication=NotSpecified;authenticationScheme=nativeAuthentication;xopenStates=false;sendTimeAsDatetime=true;trustStoreType=JKS;trustServerCertificate=false;TransparentNetworkIPResolution=true;serverNameAsACE=false;sendStringParametersAsUnicode=true;selectMethod=direct;responseBuffering=adaptive;queryTimeout=-1;packetSize=8000;multiSubnetFailover=false;loginTimeout=15;lockTimeout=-1;lastUpdateCount=true;encrypt=false;disableStatementPooling=true;databaseName=DEV;columnEncryptionSetting=Disabled;applicationName=Microsoft JDBC Driver for SQL Server;applicationIntent=readwrite;\n259- Database updated at 11/9/21, 10:19 PM. Applied 1 changeset(s), DeploymentId: 6496372605\n260  liquibase-internal::1636496372758::liquibase\n261- Database updated at 11/9/21, 10:19 PM. Applied 1 changeset(s), DeploymentId: 6496375151\n262  changelog.sql::createTable_salesTableZ::SteveZ\n263Liquibase command 'history' was executed successfully.\n```\n\n### Clicking into the DEV->QA job example from your pipeline\n\nWe run the liquibase diff command to compare the DEV and QA databases. This helps detect any drift between the databases.\n\nNotice in the log output that there are some unexpected changes: \n\ntable named bad_table\n\nprocedure named bad_proc\n\n![The diff report](https://about.gitlab.com/images/blogimages/8_LiquibaseDiff_Report.png){: .shadow.small.center}\n\nBy using the [Liquibase Pro trial license key](https://www.liquibase.com/trial), you’re able to detect any stored logic objects included in the diff report. Liquibase Pro also allows you to generate a parsable JSON output file and save it as an artifact for later use.\n\n```\n137Starting Liquibase at 22:21:10 (version 4.6.1 #98 built at 2021-11-04 20:16+0000)\n138Liquibase Version: 4.6.1\n139Liquibase Pro 4.6.1 by Liquibase licensed to customersuccess until Mon Jun 27 04:59:59 UTC 2022\n140Output saved to /home/gitlab-runner/builds/3-UvD4aX/0/szandany/sql_server/diff_between_DEV_QA.json\n141Liquibase command 'diff' was executed successfully.\n```\n\nJSON artifact output file example:\n\n```\n{\n    \"diff\": {\n        \"diffFormat\": 1,\n        \"created\": \"Wed Dec 08 20:16:53 UTC 2021\",\n        \"databases\": {\n            \"reference\": {\n                \"majorVersion\": \"14\",\n                \"minorVersion\": \"00\",\n                \"name\": \"Microsoft SQL Server\",\n                \"url\": \"jdbc:sqlserver://localhost:1433;databaseName=DEV; ...\"\n            },\n            \"target\": {\n                \"majorVersion\": \"14\",\n                \"minorVersion\": \"00\",\n                \"name\": \"Microsoft SQL Server\",\n                \"url\": \"jdbc:sqlserver://localhost:1433;databaseName=QA; ...\"\n            }\n        },\n        \"unexpectedObjects\": [\n            {\n                \"unexpectedObject\": {\n                    \"name\": \"bad_proc\",\n                    \"type\": \"storedProcedure\",\n                    \"schemaName\": \"dbo\",\n                    \"catalogName\": \"QA\"\n                }\n            },\n            {\n                \"unexpectedObject\": {\n                    \"name\": \"bad_table\",\n                    \"type\": \"table\",\n                    \"schemaName\": \"dbo\",\n                    \"catalogName\": \"QA\"\n                }\n            },\n            {\n                \"unexpectedObject\": {\n                    \"name\": \"MARKET\",\n                    \"type\": \"column\",\n                    \"relationName\": \"bad_table\",\n                    \"schemaName\": \"dbo\",\n                    \"catalogName\": \"QA\"\n                }\n            },\n            {\n                \"unexpectedObject\": {\n                    \"name\": \"ID\",\n                    \"type\": \"column\",\n                    \"relationName\": \"bad_table\",\n                    \"schemaName\": \"dbo\",\n                    \"catalogName\": \"QA\"\n                }\n            },\n            {\n                \"unexpectedObject\": {\n                    \"name\": \"NAME\",\n                    \"type\": \"column\",\n                    \"relationName\": \"bad_table\",\n                    \"schemaName\": \"dbo\",\n                    \"catalogName\": \"QA\"\n                }\n            },\n            {\n                \"unexpectedObject\": {\n                    \"name\": \"REGION\",\n                    \"type\": \"column\",\n                    \"relationName\": \"bad_table\",\n                    \"schemaName\": \"dbo\",\n                    \"catalogName\": \"QA\"\n                }\n            }\n        ],\n        \"changedObjects\": [\n            {\n                \"changedObject\": {\n                    \"name\": \"QA\",\n                    \"type\": \"catalog\",\n                    \"differences\": [\n                        {\n                            \"difference\": {\n                                \"comparedValue\": \"QA\",\n                                \"field\": \"name\",\n                                \"message\": \"name changed from 'DEV' to 'QA'\",\n                                \"referenceValue\": \"DEV\"\n                            }\n                        }\n                    ]\n                }\n            }\n        ]\n    }\n}\n\n```\n\nNote that the [Liquibase diffChangelog](https://docs.liquibase.com/commands/diffchangelog.html) can help any baseline environments that have drifted. \n\nClicking into the snapshot PROD job example, the snapshot file contains all the current schema changes represented in a JSON file. You can obtain the PROD database snapshot file to compare two states of the same database to protect against malware with drift detection.\n\n```\n58Starting Liquibase at 22:21:32 (version 4.6.1 #98 built at 2021-11-04 20:16+0000)\n59Liquibase Version: 4.6.1\n60Liquibase Pro 4.6.1 by Liquibase licensed to customersuccess until Mon Jun 27 04:59:59 UTC 2022\n61Output saved to /home/gitlab-runner/builds/3-UvD4aX/0/szandany/sql_server/snapshot_PROD.json\n62Liquibase command 'snapshot' was executed successfully. \n64Uploading artifacts for successful job00:01\n70Cleaning up project directory and file based variables00:00\n72Job succeeded\n```\n\n### Congratulations! The pipeline ran successfully.\n\nIf all the jobs are successful, you’ll see a green checkmark right next to each one.\n\nHere’s what your database changes will look like with a database SQL query tool.\n\n![The database](https://about.gitlab.com/images/blogimages/9_Database_Changes_SQL_Query_Tool.png){: .shadow.small.center}\n\n## Summing it up\n\nYou’ve now successfully run Liquibase in a GitLab pipeline to enable true CI/CD for the database. You can easily keep adding more changes to the database by adding more Liquibase changesets to the changelog, commit them to GitLab version control, and repeat the merge request process described in this tutorial to add the changes. \n\nStill have questions or want support integrating Liquibase with your Gitlab CI/CD Pipeline? Our team of database DevOps experts is happy to help! \n\n[Contact Liquibase](https://www.liquibase.com/contact)\n\n[Contact GitLab](/sales/)\n\nContact a [certified GitLab channel partner](https://www.google.com/url?q=https://partners.gitlab.com/English/directory/&sa=D&source=docs&ust=1641393355697069&usg=AOvVaw0R5mPukwMBR2dKsn3eQzqp)\n\nContact a [Liquibase channel partner](https://www.liquibase.com/partners)\n\nOther useful links: \n\n[Gitlab CI/CD setup Liquibase documentation](https://docs.liquibase.com/concepts/installation/setup-gitlab-cicd.html)\n\n[GitLab - Liquibase repository](https://gitlab.com/gitlab-com/alliances/liquibase/sandbox-projects/liquibasegitlabcicd/-/blob/master/README.md) \n\nGet a [speedy, secure database developer flow](https://www.liquibase.com/blog/secure-database-developer-flow-using-gitlab-pipelines) using GitLab pipelines & Liquibase\n\n_Author Tsvi Zandany is a Senior Solutions Architect at Liquibase_\n","engineering",[23,24,25],"integrations","CI","CD",{"slug":27,"featured":6,"template":28},"how-to-bring-devops-to-the-database-with-gitlab-and-liquibase","BlogPost","content:en-us:blog:how-to-bring-devops-to-the-database-with-gitlab-and-liquibase.yml","yaml","How To Bring Devops To The Database With Gitlab And Liquibase","content","en-us/blog/how-to-bring-devops-to-the-database-with-gitlab-and-liquibase.yml","en-us/blog/how-to-bring-devops-to-the-database-with-gitlab-and-liquibase","yml",{"_path":37,"_dir":38,"_draft":6,"_partial":6,"_locale":7,"data":39,"_id":448,"_type":30,"title":449,"_source":32,"_file":450,"_stem":451,"_extension":35},"/shared/en-us/main-navigation","en-us",{"logo":40,"freeTrial":45,"sales":50,"login":55,"items":60,"search":389,"minimal":420,"duo":439},{"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,201,206,310,370],{"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":183},"Product",true,{"dataNavLevelOne":109},"solutions",{"text":111,"config":112},"View all Solutions",{"href":113,"dataGaName":109,"dataGaLocation":44},"/solutions/",[115,140,162],{"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,152,157],{"text":150,"config":151},"Security & Compliance",{"href":145,"dataGaLocation":44,"dataGaName":150},{"text":153,"config":154},"Software Supply Chain Security",{"href":155,"dataGaLocation":44,"dataGaName":156},"/solutions/supply-chain/","Software supply chain security",{"text":158,"config":159},"Compliance & Governance",{"href":160,"dataGaLocation":44,"dataGaName":161},"/solutions/continuous-software-compliance/","Compliance and governance",{"title":163,"link":164,"items":169},"Measurement",{"config":165},{"icon":166,"href":167,"dataGaName":168,"dataGaLocation":44},"DigitalTransformation","/solutions/visibility-measurement/","visibility and measurement",[170,174,178],{"text":171,"config":172},"Visibility & Measurement",{"href":167,"dataGaLocation":44,"dataGaName":173},"Visibility and Measurement",{"text":175,"config":176},"Value Stream Management",{"href":177,"dataGaLocation":44,"dataGaName":175},"/solutions/value-stream-management/",{"text":179,"config":180},"Analytics & Insights",{"href":181,"dataGaLocation":44,"dataGaName":182},"/solutions/analytics-and-insights/","Analytics and insights",{"title":184,"items":185},"GitLab for",[186,191,196],{"text":187,"config":188},"Enterprise",{"href":189,"dataGaLocation":44,"dataGaName":190},"/enterprise/","enterprise",{"text":192,"config":193},"Small Business",{"href":194,"dataGaLocation":44,"dataGaName":195},"/small-business/","small business",{"text":197,"config":198},"Public Sector",{"href":199,"dataGaLocation":44,"dataGaName":200},"/solutions/public-sector/","public sector",{"text":202,"config":203},"Pricing",{"href":204,"dataGaName":205,"dataGaLocation":44,"dataNavLevelOne":205},"/pricing/","pricing",{"text":207,"config":208,"link":210,"lists":214,"feature":297},"Resources",{"dataNavLevelOne":209},"resources",{"text":211,"config":212},"View all resources",{"href":213,"dataGaName":209,"dataGaLocation":44},"/resources/",[215,247,269],{"title":216,"items":217},"Getting started",[218,223,228,233,238,243],{"text":219,"config":220},"Install",{"href":221,"dataGaName":222,"dataGaLocation":44},"/install/","install",{"text":224,"config":225},"Quick start guides",{"href":226,"dataGaName":227,"dataGaLocation":44},"/get-started/","quick setup checklists",{"text":229,"config":230},"Learn",{"href":231,"dataGaLocation":44,"dataGaName":232},"https://university.gitlab.com/","learn",{"text":234,"config":235},"Product documentation",{"href":236,"dataGaName":237,"dataGaLocation":44},"https://docs.gitlab.com/","product documentation",{"text":239,"config":240},"Best practice videos",{"href":241,"dataGaName":242,"dataGaLocation":44},"/getting-started-videos/","best practice videos",{"text":244,"config":245},"Integrations",{"href":246,"dataGaName":23,"dataGaLocation":44},"/integrations/",{"title":248,"items":249},"Discover",[250,255,259,264],{"text":251,"config":252},"Customer success stories",{"href":253,"dataGaName":254,"dataGaLocation":44},"/customers/","customer success stories",{"text":256,"config":257},"Blog",{"href":258,"dataGaName":5,"dataGaLocation":44},"/blog/",{"text":260,"config":261},"Remote",{"href":262,"dataGaName":263,"dataGaLocation":44},"https://handbook.gitlab.com/handbook/company/culture/all-remote/","remote",{"text":265,"config":266},"TeamOps",{"href":267,"dataGaName":268,"dataGaLocation":44},"/teamops/","teamops",{"title":270,"items":271},"Connect",[272,277,282,287,292],{"text":273,"config":274},"GitLab Services",{"href":275,"dataGaName":276,"dataGaLocation":44},"/services/","services",{"text":278,"config":279},"Community",{"href":280,"dataGaName":281,"dataGaLocation":44},"/community/","community",{"text":283,"config":284},"Forum",{"href":285,"dataGaName":286,"dataGaLocation":44},"https://forum.gitlab.com/","forum",{"text":288,"config":289},"Events",{"href":290,"dataGaName":291,"dataGaLocation":44},"/events/","events",{"text":293,"config":294},"Partners",{"href":295,"dataGaName":296,"dataGaLocation":44},"/partners/","partners",{"backgroundColor":298,"textColor":299,"text":300,"image":301,"link":305},"#2f2a6b","#fff","Insights for the future of software development",{"altText":302,"config":303},"the source promo card",{"src":304},"/images/navigation/the-source-promo-card.svg",{"text":306,"config":307},"Read the latest",{"href":308,"dataGaName":309,"dataGaLocation":44},"/the-source/","the source",{"text":311,"config":312,"lists":314},"Company",{"dataNavLevelOne":313},"company",[315],{"items":316},[317,322,328,330,335,340,345,350,355,360,365],{"text":318,"config":319},"About",{"href":320,"dataGaName":321,"dataGaLocation":44},"/company/","about",{"text":323,"config":324,"footerGa":327},"Jobs",{"href":325,"dataGaName":326,"dataGaLocation":44},"/jobs/","jobs",{"dataGaName":326},{"text":288,"config":329},{"href":290,"dataGaName":291,"dataGaLocation":44},{"text":331,"config":332},"Leadership",{"href":333,"dataGaName":334,"dataGaLocation":44},"/company/team/e-group/","leadership",{"text":336,"config":337},"Team",{"href":338,"dataGaName":339,"dataGaLocation":44},"/company/team/","team",{"text":341,"config":342},"Handbook",{"href":343,"dataGaName":344,"dataGaLocation":44},"https://handbook.gitlab.com/","handbook",{"text":346,"config":347},"Investor relations",{"href":348,"dataGaName":349,"dataGaLocation":44},"https://ir.gitlab.com/","investor relations",{"text":351,"config":352},"Trust Center",{"href":353,"dataGaName":354,"dataGaLocation":44},"/security/","trust center",{"text":356,"config":357},"AI Transparency Center",{"href":358,"dataGaName":359,"dataGaLocation":44},"/ai-transparency-center/","ai transparency center",{"text":361,"config":362},"Newsletter",{"href":363,"dataGaName":364,"dataGaLocation":44},"/company/contact/","newsletter",{"text":366,"config":367},"Press",{"href":368,"dataGaName":369,"dataGaLocation":44},"/press/","press",{"text":371,"config":372,"lists":373},"Contact us",{"dataNavLevelOne":313},[374],{"items":375},[376,379,384],{"text":51,"config":377},{"href":53,"dataGaName":378,"dataGaLocation":44},"talk to sales",{"text":380,"config":381},"Get help",{"href":382,"dataGaName":383,"dataGaLocation":44},"/support/","get help",{"text":385,"config":386},"Customer portal",{"href":387,"dataGaName":388,"dataGaLocation":44},"https://customers.gitlab.com/customers/sign_in/","customer portal",{"close":390,"login":391,"suggestions":398},"Close",{"text":392,"link":393},"To search repositories and projects, login to",{"text":394,"config":395},"gitlab.com",{"href":58,"dataGaName":396,"dataGaLocation":397},"search login","search",{"text":399,"default":400},"Suggestions",[401,403,407,409,413,417],{"text":73,"config":402},{"href":78,"dataGaName":73,"dataGaLocation":397},{"text":404,"config":405},"Code Suggestions (AI)",{"href":406,"dataGaName":404,"dataGaLocation":397},"/solutions/code-suggestions/",{"text":125,"config":408},{"href":127,"dataGaName":125,"dataGaLocation":397},{"text":410,"config":411},"GitLab on AWS",{"href":412,"dataGaName":410,"dataGaLocation":397},"/partners/technology-partners/aws/",{"text":414,"config":415},"GitLab on Google Cloud",{"href":416,"dataGaName":414,"dataGaLocation":397},"/partners/technology-partners/google-cloud-platform/",{"text":418,"config":419},"Why GitLab?",{"href":86,"dataGaName":418,"dataGaLocation":397},{"freeTrial":421,"mobileIcon":426,"desktopIcon":431,"secondaryButton":434},{"text":422,"config":423},"Start free trial",{"href":424,"dataGaName":49,"dataGaLocation":425},"https://gitlab.com/-/trials/new/","nav",{"altText":427,"config":428},"Gitlab Icon",{"src":429,"dataGaName":430,"dataGaLocation":425},"/images/brand/gitlab-logo-tanuki.svg","gitlab icon",{"altText":427,"config":432},{"src":433,"dataGaName":430,"dataGaLocation":425},"/images/brand/gitlab-logo-type.svg",{"text":435,"config":436},"Get Started",{"href":437,"dataGaName":438,"dataGaLocation":425},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com/compare/gitlab-vs-github/","get started",{"freeTrial":440,"mobileIcon":444,"desktopIcon":446},{"text":441,"config":442},"Learn more about GitLab Duo",{"href":78,"dataGaName":443,"dataGaLocation":425},"gitlab duo",{"altText":427,"config":445},{"src":429,"dataGaName":430,"dataGaLocation":425},{"altText":427,"config":447},{"src":433,"dataGaName":430,"dataGaLocation":425},"content:shared:en-us:main-navigation.yml","Main Navigation","shared/en-us/main-navigation.yml","shared/en-us/main-navigation",{"_path":453,"_dir":38,"_draft":6,"_partial":6,"_locale":7,"title":454,"button":455,"image":459,"config":462,"_id":464,"_type":30,"_source":32,"_file":465,"_stem":466,"_extension":35},"/shared/en-us/banner","is now in public beta!",{"text":84,"config":456},{"href":457,"dataGaName":458,"dataGaLocation":44},"/gitlab-duo/agent-platform/","duo banner",{"config":460},{"src":461},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1753720689/somrf9zaunk0xlt7ne4x.svg",{"layout":463},"release","content:shared:en-us:banner.yml","shared/en-us/banner.yml","shared/en-us/banner",{"_path":468,"_dir":38,"_draft":6,"_partial":6,"_locale":7,"data":469,"_id":674,"_type":30,"title":675,"_source":32,"_file":676,"_stem":677,"_extension":35},"/shared/en-us/main-footer",{"text":470,"source":471,"edit":477,"contribute":482,"config":487,"items":492,"minimal":666},"Git is a trademark of Software Freedom Conservancy and our use of 'GitLab' is under license",{"text":472,"config":473},"View page source",{"href":474,"dataGaName":475,"dataGaLocation":476},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/","page source","footer",{"text":478,"config":479},"Edit this page",{"href":480,"dataGaName":481,"dataGaLocation":476},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/content/","web ide",{"text":483,"config":484},"Please contribute",{"href":485,"dataGaName":486,"dataGaLocation":476},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/CONTRIBUTING.md/","please contribute",{"twitter":488,"facebook":489,"youtube":490,"linkedin":491},"https://twitter.com/gitlab","https://www.facebook.com/gitlab","https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg","https://www.linkedin.com/company/gitlab-com",[493,516,573,602,636],{"title":62,"links":494,"subMenu":499},[495],{"text":496,"config":497},"DevSecOps platform",{"href":71,"dataGaName":498,"dataGaLocation":476},"devsecops platform",[500],{"title":202,"links":501},[502,506,511],{"text":503,"config":504},"View plans",{"href":204,"dataGaName":505,"dataGaLocation":476},"view plans",{"text":507,"config":508},"Why Premium?",{"href":509,"dataGaName":510,"dataGaLocation":476},"/pricing/premium/","why premium",{"text":512,"config":513},"Why Ultimate?",{"href":514,"dataGaName":515,"dataGaLocation":476},"/pricing/ultimate/","why ultimate",{"title":517,"links":518},"Solutions",[519,524,527,529,534,539,543,546,550,555,557,560,563,568],{"text":520,"config":521},"Digital transformation",{"href":522,"dataGaName":523,"dataGaLocation":476},"/topics/digital-transformation/","digital transformation",{"text":150,"config":525},{"href":145,"dataGaName":526,"dataGaLocation":476},"security & compliance",{"text":139,"config":528},{"href":121,"dataGaName":122,"dataGaLocation":476},{"text":530,"config":531},"Agile development",{"href":532,"dataGaName":533,"dataGaLocation":476},"/solutions/agile-delivery/","agile delivery",{"text":535,"config":536},"Cloud transformation",{"href":537,"dataGaName":538,"dataGaLocation":476},"/topics/cloud-native/","cloud transformation",{"text":540,"config":541},"SCM",{"href":135,"dataGaName":542,"dataGaLocation":476},"source code management",{"text":125,"config":544},{"href":127,"dataGaName":545,"dataGaLocation":476},"continuous integration & delivery",{"text":547,"config":548},"Value stream management",{"href":177,"dataGaName":549,"dataGaLocation":476},"value stream management",{"text":551,"config":552},"GitOps",{"href":553,"dataGaName":554,"dataGaLocation":476},"/solutions/gitops/","gitops",{"text":187,"config":556},{"href":189,"dataGaName":190,"dataGaLocation":476},{"text":558,"config":559},"Small business",{"href":194,"dataGaName":195,"dataGaLocation":476},{"text":561,"config":562},"Public sector",{"href":199,"dataGaName":200,"dataGaLocation":476},{"text":564,"config":565},"Education",{"href":566,"dataGaName":567,"dataGaLocation":476},"/solutions/education/","education",{"text":569,"config":570},"Financial services",{"href":571,"dataGaName":572,"dataGaLocation":476},"/solutions/finance/","financial services",{"title":207,"links":574},[575,577,579,581,584,586,588,590,592,594,596,598,600],{"text":219,"config":576},{"href":221,"dataGaName":222,"dataGaLocation":476},{"text":224,"config":578},{"href":226,"dataGaName":227,"dataGaLocation":476},{"text":229,"config":580},{"href":231,"dataGaName":232,"dataGaLocation":476},{"text":234,"config":582},{"href":236,"dataGaName":583,"dataGaLocation":476},"docs",{"text":256,"config":585},{"href":258,"dataGaName":5,"dataGaLocation":476},{"text":251,"config":587},{"href":253,"dataGaName":254,"dataGaLocation":476},{"text":260,"config":589},{"href":262,"dataGaName":263,"dataGaLocation":476},{"text":273,"config":591},{"href":275,"dataGaName":276,"dataGaLocation":476},{"text":265,"config":593},{"href":267,"dataGaName":268,"dataGaLocation":476},{"text":278,"config":595},{"href":280,"dataGaName":281,"dataGaLocation":476},{"text":283,"config":597},{"href":285,"dataGaName":286,"dataGaLocation":476},{"text":288,"config":599},{"href":290,"dataGaName":291,"dataGaLocation":476},{"text":293,"config":601},{"href":295,"dataGaName":296,"dataGaLocation":476},{"title":311,"links":603},[604,606,608,610,612,614,616,620,625,627,629,631],{"text":318,"config":605},{"href":320,"dataGaName":313,"dataGaLocation":476},{"text":323,"config":607},{"href":325,"dataGaName":326,"dataGaLocation":476},{"text":331,"config":609},{"href":333,"dataGaName":334,"dataGaLocation":476},{"text":336,"config":611},{"href":338,"dataGaName":339,"dataGaLocation":476},{"text":341,"config":613},{"href":343,"dataGaName":344,"dataGaLocation":476},{"text":346,"config":615},{"href":348,"dataGaName":349,"dataGaLocation":476},{"text":617,"config":618},"Sustainability",{"href":619,"dataGaName":617,"dataGaLocation":476},"/sustainability/",{"text":621,"config":622},"Diversity, inclusion and belonging (DIB)",{"href":623,"dataGaName":624,"dataGaLocation":476},"/diversity-inclusion-belonging/","Diversity, inclusion and belonging",{"text":351,"config":626},{"href":353,"dataGaName":354,"dataGaLocation":476},{"text":361,"config":628},{"href":363,"dataGaName":364,"dataGaLocation":476},{"text":366,"config":630},{"href":368,"dataGaName":369,"dataGaLocation":476},{"text":632,"config":633},"Modern Slavery Transparency Statement",{"href":634,"dataGaName":635,"dataGaLocation":476},"https://handbook.gitlab.com/handbook/legal/modern-slavery-act-transparency-statement/","modern slavery transparency statement",{"title":637,"links":638},"Contact Us",[639,642,644,646,651,656,661],{"text":640,"config":641},"Contact an expert",{"href":53,"dataGaName":54,"dataGaLocation":476},{"text":380,"config":643},{"href":382,"dataGaName":383,"dataGaLocation":476},{"text":385,"config":645},{"href":387,"dataGaName":388,"dataGaLocation":476},{"text":647,"config":648},"Status",{"href":649,"dataGaName":650,"dataGaLocation":476},"https://status.gitlab.com/","status",{"text":652,"config":653},"Terms of use",{"href":654,"dataGaName":655,"dataGaLocation":476},"/terms/","terms of use",{"text":657,"config":658},"Privacy statement",{"href":659,"dataGaName":660,"dataGaLocation":476},"/privacy/","privacy statement",{"text":662,"config":663},"Cookie preferences",{"dataGaName":664,"dataGaLocation":476,"id":665,"isOneTrustButton":107},"cookie preferences","ot-sdk-btn",{"items":667},[668,670,672],{"text":652,"config":669},{"href":654,"dataGaName":655,"dataGaLocation":476},{"text":657,"config":671},{"href":659,"dataGaName":660,"dataGaLocation":476},{"text":662,"config":673},{"dataGaName":664,"dataGaLocation":476,"id":665,"isOneTrustButton":107},"content:shared:en-us:main-footer.yml","Main Footer","shared/en-us/main-footer.yml","shared/en-us/main-footer",[679],{"_path":680,"_dir":681,"_draft":6,"_partial":6,"_locale":7,"content":682,"config":686,"_id":688,"_type":30,"title":18,"_source":32,"_file":689,"_stem":690,"_extension":35},"/en-us/blog/authors/tsvi-zandany","authors",{"name":18,"config":683},{"headshot":684,"ctfId":685},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749659488/Blog/Author%20Headshots/gitlab-logo-extra-whitespace.png","Tsvi-Zandany",{"template":687},"BlogAuthor","content:en-us:blog:authors:tsvi-zandany.yml","en-us/blog/authors/tsvi-zandany.yml","en-us/blog/authors/tsvi-zandany",{"_path":692,"_dir":38,"_draft":6,"_partial":6,"_locale":7,"header":693,"eyebrow":694,"blurb":695,"button":696,"secondaryButton":700,"_id":702,"_type":30,"title":703,"_source":32,"_file":704,"_stem":705,"_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":697},{"href":698,"dataGaName":49,"dataGaLocation":699},"https://gitlab.com/-/trial_registrations/new?glm_content=default-saas-trial&glm_source=about.gitlab.com/","feature",{"text":51,"config":701},{"href":53,"dataGaName":54,"dataGaLocation":699},"content:shared:en-us:next-steps.yml","Next Steps","shared/en-us/next-steps.yml","shared/en-us/next-steps",1754424495250]