<!-- llms-index: https://docs.gradle.com/develocity/llms.txt -->

<a id="component-eol-banner"></a>

You are viewing **Develocity Documentation 2025.3**. To view the latest available version of the docs, see [2026.1](https://docs.gradle.com/develocity/2026.1/).

# User-Managed Database Migration Guide

<a id="preamble"></a>

By default, Develocity will store data in a database that runs in a container as part of the Develocity installation, and which stores its data in a local file system or persistent volume. This is referred to as the “embedded database”. Starting with Develocity 2021.3, it’s possible to instead store data in a database that’s outside of the Develocity application. This is referred to as a “user-managed database”.

This document describes how to switch a Develocity instance that has data stored in its embedded database to using a user-managed database, and migrating the data to the new database.

It is strongly recommended to read the entire guide before starting any migration steps.

<a id="data_to_be_migrated"></a>

## Data to be migrated

There are several different ways to migrate data presented in this guide, all attempting to solve a single problem: migrating a potentially large set of data with minimal service downtime.

Typically, the vast majority of data in a Develocity database is Build Scan data, which can be orders of magnitude larger than the rest. For example, some Develocity installations have terabytes of Build Scan data, with the rest in the order of megabytes. However, the rest of data in the database is more important for continuous operation. This is data such as app configuration, Build Cache node registration and topology, users, permissions and access keys, which are important to migrate and have available when switching between databases.

Many installations will have a small enough database that they can follow the first and simplest strategy of taking down the service and restoring a database backup to a new database. Other strategies involve either skipping migrating Build Scan data completely, or copying it gradually after switching to using the new database.

<a id="data-not-migrated"></a>

## Data not migrated

Built-in Build Cache entries aren’t migrated with any of the strategies in this document. It’s assumed that these will be repopulated by running the tasks or goals again in the relevant builds, and that this is an acceptable cost when doing this sort of system change.

Contact Develocity Support if this is of concern for your installation.

<a id="prerequisites"></a>

## Prerequisites

<a id="develocity-version"></a>

### Develocity version

Support for a user-managed database started with Develocity 2021.3. The system should be running at least that version. We recommend that you upgrade to the latest version of Develocity before performing a user-managed database migration.

Some migration strategies involve setting up a second Develocity instance. In these cases, the two instances should be running the same Develocity version.

<a id="database-scripts"></a>

### Database scripts

All migration strategies in this guide require running some scripts to set up the new database and copy over some data and configuration settings. Download them from [the appendix](#database_setup_download) before starting the migration.

<a id="user_managed_database_instance"></a>

### User-managed database instance

This guide assumes that you have a [compatible](#postgresql_version_compatibility) PostgreSQL database instance ready to migrate data to. A specific database doesn’t need to have been created (using e.g. `CREATE DATABASE`) - this will happen as part of the steps below. For more details on database setup, see the relevant section in the [Standalone installation manual](https://docs.gradle.com/develocity/2025.3/installation/standalone-installation/#database) or the [Kubernetes installation manual](https://docs.gradle.com/develocity/2025.3/installation/kubernetes-installation/#database).

> [!NOTE]
> Using [PgBouncer](https://www.pgbouncer.org/) with a user managed database isn’t supported. Develocity uses and depends on PostgreSQL connection parameters that aren’t supported by PgBouncer.

<a id="postgresql_version_compatibility"></a>

#### PostgreSQL version compatibility

Develocity versions 2025.3 and later support PostgreSQL 14, 15, 16, and 17.

Develocity versions 2024.3 to 2025.2 are compatible with PostgreSQL 14, 15, 16, and 17. These Develocity versions will work with PostgreSQL versions 12 and 13, but they are deprecated and will trigger a warning in the UI directing you to upgrade the database to at least PostgreSQL 14.

Develocity versions 2021.3 to 2022.1.1 are compatible with PostgreSQL version 12.

Develocity versions 2021.2 and earlier are compatible with PostgreSQL 11.

Note that [PostgreSQL 12 is now EOL and will no longer receive security and bug fixes](https://www.postgresql.org/about/news/postgresql-172-166-1510-1415-1318-and-1222-released-2965/). PostgreSQL 13 [will become EOL in November 2025](https://www.postgresql.org/support/versioning/). If your Develocity database is running PostgreSQL 12 or 13, please [upgrade your database instance](#upgrading_postgresql) to at least version 14.

> [!WARNING]
> Do not use the specific PostgreSQL minor versions that were released on Nov 14th, 2024. These versions of PostgreSQL have a bug that breaks login roles, causing database objects to be created with unexpected ownership. This bug was fixed in an out-of-cycle release.

<a id="additional-develocity-instance"></a>

### Additional Develocity instance

Some migration strategies described below involve copying Build Scan data after the initial migration of everything else. This requires setting up a new Develocity instance. Check the feasibility, time and cost of setting up a new instance when deciding on migration strategy.

<a id="instance_promotion"></a>

### Develocity instance promotion

Some migration strategies described below require promoting a new Develocity instance to become your main instance that builds connect to. For example, Build Scans will be published to this new instance once the promotion happens. This switch can occur in several ways, depending on your infrastructure setup:

*   If you have a reverse proxy of some sort that sits in front of Develocity, this can likely be easily configured to point to a different Develocity instance.
    
*   Many setups use a DNS entry to point to their primary Develocity instance that’s unrelated to the specific host that Develocity is installed on. Promoting a new instance then involves updating the DNS entry.
    
*   Alternatively, build configuration can be updated to point to a different instance. All build plugins and extensions, Build Cache nodes and Test Distribution agents must be updated to point to the new server. This is often more onerous than updating network infrastructure, but may be a reasonable strategy, depending on how centralized or duplicated your organization’s build configuration is.
    

If there is no easy promotion path, there are migration strategies that allow use of the existing instance, with certain tradeoffs. Before proceeding with a migration, you should understand the possible promotion strategies for your infrastructure to allow evaluation of the tradeoffs described below.

<a id="service-downtime-during-a-backup"></a>

### Service downtime during a backup

Some migration strategies below involve taking a backup of the embedded database to allow setting up a second Develocity instance. Knowledge of your current backup duration is useful here, to help in evaluating likely downtime during the migration. To get an idea of your current backup duration, you can [inspect the timestamps in the backup history logs](#backup_history_logs), which are written by the `database-tasks` container.

<a id="build-scan-copying"></a>

### Build Scan copying

Some migration strategies below involve copying Build Scan data into the new database. This requires a host on which to run `` develocityctl` ``. This may be a host with Develocity installed, or may need to be a different host, depending on your network settings and Develocity instances. See the [appendix](#pre_copying) for more details.

<a id="disk-space-cleanup"></a>

### Disk space cleanup

In all strategies below, the data directory or persistent volume on which the embedded database is stored is left in place until a final cleanup step. This means that if there is any unexpected issue during the migration, the original data is still where it was so it should be possible to revert any changes and resume using the embedded database. Once all other steps have been completed it should be safe to clean this up as described below.

<a id="migration-strategies"></a>

## Migration strategies

Different strategies are presented here, each with different trade-offs. Read through them and choose the best for your build and network infrastructure.

Recommended options:

*   Use the [Migrate all data up-front strategy](#strategy_migrate_all_up_front) if your database is small enough. See [here](#test_full_migrate_downtime) to measure how long the migration would take.
    
*   Use the [Migrate all non-Build-Scan data strategy](#strategy_migrate_non_build_scan) if you can tolerate losing historical Build Scan data.
    
*   Use the [Restore backup to a secondary Develocity instance, connect primary to new database strategy](#strategy_detached_secondary_no_copy) if you can tolerate historical Build Scan data being only available in a secondary instance, can set up such an instance, and can tolerate downtime while a backup is run.
    
*   If you need historical and recent Build Scan data together on the same Develocity instance:
    
    *   Use the [Set up and promote new Develocity instance, copy Build Scan data to it strategy](#strategy_copy_to_new_instance) if you can easily promote a new instance
        
    *   Use the [Copy Build Scan data from second, temporary instance strategy](#strategy_copy_from_new_temp_instance) if you cannot easily promote a new instance
        
    

Please contact Develocity support for assistance in picking the correct migration strategy for your installation.

<a id="strategy_migrate_all_up_front"></a>

## Strategy 1: Migrate all data up-front, offline

This approach migrates all data in one go, while the application is unavailable.

<a id="tradeoffs"></a>

### Tradeoffs

Pros:

*   All data copied in a single step
    

Cons:

*   Requires downtime while data is dumped and restored. This will be significant for installations with a lot of data.
    

<a id="steps"></a>

### Steps

1.  Consider doing a [test run](#test_full_migrate_downtime), to measure the likely downtime and ensure that it is acceptable for your organization.
    
2.  Perform [initial database setup](#:initial_database_setup).
    
3.  [Stop the enterprise app while leaving the database running](#stop_app_leave_db_up). This ensures that no data is lost when switching to the new database. Your Develocity instance will be unavailable at this point.
    
4.  Run the [data migration script](#run_migration_script), making sure to pass the `--include-build-scans` parameter. This copies all data to the new database.
    
5.  [Configure your Develocity instance to point to your new database.](#configure_ge_to_connect_to_new_database)
    
6.  Wait for Develocity to complete restarting.
    
7.  [Smoke test](#smoke_test) your Develocity instance to ensure that it’s operational.
    
8.  Test that your normal builds are functioning, including Build Scan publishing, Build Cache usage and Test Distribution, depending on which features are used in your builds.
    
9.  Once you are satisfied that the instance attached to the new database is fully operational and has the correct data, it is safe to [clean up the old data](#data_cleanup).
    

<a id="strategy_migrate_non_build_scan"></a>

## Strategy 2: Migrate all non-Build-Scan data

This approach migrates all data except for Build Scan data, which isn’t retained.

<a id="tradeoffs-2"></a>

### Tradeoffs

Pros:

*   Minimal downtime
    

Cons:

*   Build Scan data isn’t retained
    

<a id="steps-2"></a>

### Steps

1.  Perform [initial database setup](#:initial_database_setup).
    
2.  [Stop the enterprise app while leaving the database running](#stop_app_leave_db_up). This ensures that no data is lost when switching to the new database. Your Develocity instance will be unavailable at this point.
    
3.  Run the [data migration script](#run_migration_script). This copies all non Build Scan data to the new database.
    
4.  [Configure your Develocity instance to point to your new database.](#configure_ge_to_connect_to_new_database)
    
5.  Wait for Develocity to complete restarting.
    
6.  [Smoke test](#smoke_test) your Develocity instance to ensure that it’s operational.
    
7.  Test that your normal builds are functioning, including Build Scan publishing, Build Cache usage and Test Distribution, depending on which features are used in your builds.
    
8.  Once you are satisfied that the instance attached to the new database is fully operational and has the correct data, it is safe to [clean up the old data](#data_cleanup).
    

<a id="strategy_detached_secondary_no_copy"></a>

## Strategy 3: Restore backup to a secondary Develocity instance, connect primary to new database

This approach takes a backup of the data, starts a new, temporary instance of Develocity with that data, and configures the existing instance to point to the user-managed database. All new data will be on the primary instance, and historical data can be viewed on the secondary instance. After a period of time, the secondary instance can be decommissioned.

<a id="tradeoffs-3"></a>

### Tradeoffs

Pros

*   All data is available immediately
    
*   No need to promote an instance
    

Cons:

*   Historical data is only available on the second instance
    
*   Resources are required for the second instance as long as the historical data on it is needed
    
*   Service will be down while the database backup is taken
    
*   A potentially large backup must be copied to a new instance
    

<a id="steps-3"></a>

### Steps

1.  Perform [initial database setup](#:initial_database_setup).
    
2.  Create and install a new Develocity instance. This instance will be a secondary Develocity instance that provides access to historical data. It will need enough storage to hold both a copy of the database and a backup of it. Configure the instance to connect to its embedded database.
    
3.  On the primary instance, [stop the enterprise app while leaving the database running](#stop_app_leave_db_up). This ensures that no data is lost when switching to the new database. Your Develocity instance will be unavailable at this point.
    
4.  Run the [data migration script](#run_migration_script).
    
5.  Take a backup of the database on your primary Develocity instance. See the [administration manual for Helm-based installations](https://docs.gradle.com/develocity/2025.3/administration/admin-manual/#backups_embedded_creating).
    
6.  [Configure the primary Develocity instance to point to the new database.](#configure_ge_to_connect_to_new_database)
    
7.  [Smoke test](#smoke_test) the primary instance to ensure that it’s operational.
    
8.  Test that your normal builds are functioning, including Build Scan publishing, Build Cache usage and Test Distribution, depending on which features are used in your builds.
    
9.  At this point, your primary instance is now connected to your new database and is storing its data there. New Build Scan data will be published to the database, but Build Scan history will not be present.
    
10.  Copy the backup to your secondary Develocity instance.
     
11.  Stop Develocity on the secondary instance.
     
12.  Restore the backup on your secondary instance. See the [administration manual for Helm-based installations](https://docs.gradle.com/develocity/2025.3/administration/admin-manual/#backups_embedded_restoring).
     
13.  Start the secondary instance up again.
     
14.  At this point, you can access historical Build Scans and trends data up to the backup point on the secondary instance.
     
15.  Keep the secondary instance running as long as the historical data is useful. It can be decommissioned on your preferred schedule.
     

<a id="strategy_copy_to_new_instance"></a>

## Strategy 4: Set up and promote new Develocity instance, copy Build Scan data to it

This approach migrates all non Build Scan data and configuration to a new user-managed database, starts a new instance of Develocity connected to that database, promotes the new instance, then copies Build Scan data to the new instance.

<a id="tradeoffs-4"></a>

### Tradeoffs

Pros

*   All data is copied eventually
    
*   Second volume of storage capable of holding the database isn’t required
    
*   Short downtime
    

Cons:

*   Historical data is only available on the original instance initially
    
*   Resources for a second Develocity instance are required while Build Scan data is copied
    
*   Requires ability to promote a new instance
    

<a id="steps-4"></a>

### Steps

1.  Perform [initial database setup](#:initial_database_setup).
    
2.  Create and install a new Develocity instance. This instance will be the new Develocity instance at the end of this procedure and so it needs to be provisioned (CPU, memory) and the current instance, with the exception that it doesn’t need a large disk to handle Build Scan data in the database. At this stage, install it configured to use the embedded database.
    
3.  Ensure that any [pre-promotion steps](#pre_promotion) have been completed.
    
4.  Ensure that you have run through the [Build Scan pre-copy verification steps](#pre_copying).
    
5.  On the original instance, [stop the enterprise app while leaving the database running](#stop_app_leave_db_up). This ensures that no data is lost when switching to the new database. Your Develocity instance will be unavailable at this point.
    
6.  Run the [data migration script](#run_migration_script).
    
7.  [Configure the new Develocity instance to point to the new database.](#configure_ge_to_connect_to_new_database)
    
8.  [Smoke test](#smoke_test) the new instance to ensure that it’s operational.
    
9.  Promote the new Develocity instance, using whatever promotion strategy is suitable for your environment, as discussed [above](#instance_promotion).
    
10.  Test that your normal builds are functioning using the new instance, including Build Scan publishing, Build Cache usage and Test Distribution, depending on which features are used in your builds.
     
11.  At this point, your new instance is now the main Develocity instance for you organization. New Build Scan data will be published to it, but Build Scan history won’t be present. If your original instance’s web interface is still available after the new instance is promoted, historical Build Scan data up to the switchover point will be available on that URL.
     
12.  Run [`develocityctl`](#develocityctl). `develocityctl` will copy Build Scans from your original instance to the new one, starting with the most recent first, to restore trends data for the most recent Build Scans first.
     
13.  At any point, if you decide that enough historical data has been copied to the new instance, you can terminate `develocityctl`.
     
14.  Once you are satisfied that the new instance is fully operational and has the correct data, the original instance can be decommissioned on your preferred schedule.
     

<a id="strategy_copy_from_new_temp_instance"></a>

## Strategy 5: Copy Build Scan data from second, temporary instance

This approach takes a backup of the data, starts a new, temporary instance of Develocity with that data, configures the existing instance to point to the user-managed database and then copies Build Scan data from the temporary instance.

<a id="tradeoffs-5"></a>

### Tradeoffs

Pros

*   All data is copied eventually
    
*   No need to promote a new instance
    

Cons:

*   Historical data is only available on the second instance initially
    
*   Resources for a second Develocity instance are required while Build Scan data is copied
    
*   Service will be down while the database backup is taken
    
*   Potentially large backup must be copied to new instance
    

<a id="steps-5"></a>

### Steps

1.  Perform [initial database setup](#:initial_database_setup).
    
2.  Create and install a new Develocity instance. This instance will be a temporary Develocity instance that’s used by `develocityctl` to copy Build Scan data into the new database. It will need enough storage to hold both a copy of the database and a backup of it. Configure the instance to connect to its embedded database.
    
3.  Ensure that you have run through the [Build Scan pre-copy verification steps](#pre_copying).
    
4.  On your original instance, [stop the enterprise app while leaving the database running](#stop_app_leave_db_up). This ensures that no data is lost when switching to the new database. Your Develocity instance will be unavailable at this point.
    
5.  Run the [data migration script](#run_migration_script).
    
6.  Take a backup of the database on your original Develocity instance. See the [administration manual for Helm-based installations](https://docs.gradle.com/develocity/2025.3/administration/admin-manual/#backups_embedded_creating).
    
7.  [Configure the original Develocity instance to point to the new database.](#configure_ge_to_connect_to_new_database)
    
8.  [Smoke test](#smoke_test) the original instance to ensure that it’s operational.
    
9.  Test that your normal builds are functioning, including Build Scan publishing, Build Cache usage and Test Distribution, depending on which features are used in your builds.
    
10.  At this point, your original instance is now connected to your database and is storing its data there. New Build Scan data will be published to it, but Build Scan history will not be present.
     
11.  Copy the backup to your new Develocity instance.
     
12.  Stop Develocity on the new instance.
     
13.  Restore the backup on your new instance. See the [administration manual for Helm-based installations](https://docs.gradle.com/develocity/2025.3/administration/admin-manual/#backups_embedded_restoring).
     
14.  Start the new instance up again.
     
15.  At this point, you can access historical Build Scans and trends data up to the backup point on the new instance if necessary.
     
16.  Start [`develocityctl`](#develocityctl). Develocity will copy Build Scan data from your new, temporary instance back to the original instance, which will store them into the new database, starting with the most recent first, to restore trends data for the most recent Build Scans first.
     
17.  At any point, if you decide that enough historical data has been copied to the new database, you can terminate `develocityctl`.
     
18.  Once you are satisfied that the new database is fully operational and has the correct data, the temporary Develocity instance can be decommissioned at your preferred schedule.
     
19.  It is also safe to [clean up the old data](#data_cleanup) on the original instance at this point.
     

* * *

If you have any questions or need any assistance contact the Develocity support team or your customer success representative.

<a id="test_full_migrate_downtime"></a>

## Appendix A: Testing a full migration to determine likely downtime

This method tests how long the system would likely be unavailable during a migration by performing one as a test run.

1.  Perform [initial database setup](#:initial_database_setup). If you aren’t providing superuser credentials for the database to Develocity, set the passwords on the new accounts.
    
2.  Run the [data migration script](#run_migration_script), ensuring that Build Scan data is copied, logging the starting and ending time. For example:
    
    ```shell
    date ; ./migrate-from-embedded.sh --include-build-scans [other args] ; date
    ```
    
    > [!NOTE]
    > The `time` utility can also be used to measure duration, if it’s available in your environment.
    
3.  At any point, if the process has taken longer than would be acceptable, it may be terminated.
    

When the script completes, the difference between the initial and final logged timestamps is an estimate of how long the system would be unavailable if data is migrated in this fashion. This can then be used to determine if a full up-front migration is a viable strategy for your organization.

After completing the test, the user-managed database should be dropped and recreated to have a clean database for the final migration.

<a id=":initial_database_setup"></a>

## Appendix B: Initial database setup

Normally, when connecting to a user-managed database, Develocity is configured with database superuser credentials. These are used to set up database schemas and less privileged accounts that it then uses to access the database day-to-day.

It is possible to configure Develocity without providing superuser credentials. In that configuration, once per major release, a database setup script must be run manually. This sets up the schemas and other accounts, and Develocity is then configured with credentials for the other accounts.

When performing any of the migration strategies in this document, this script must also be run.

<a id="steps-6"></a>

### Steps

1.  Download the database script bundle from [the appendix](#database_setup_download).
    
2.  Create your database using `CREATE DATABASE` or an equivalent in your database provider interface.
    
3.  Run the setup script on a host that can connect to your database:
    
    ```shell
    PGPASSWORD="xxx-postgres-user-password" ./setup.sh --host=db.myhost.com
    ```
    

Run the script without arguments to see full options (e.g. different username, non-default port etc).  
This will create two accounts: `ge_app` and `ge_migrator`.

1.  If your Develocity installation will not be configured with superuser credentials, set the passwords for the two new accounts, using `psql` or an equivalent query tool:
    
    ```shell
    psql -h db.myhost.com -U postgres ALTER USER ge_app PASSWORD 'the_app_password'
    psql -h db.myhost.com -U postgres ALTER USER ge_migrator PASSWORD 'the_migrator_password'
    psql -h db.myhost.com -U postgres ALTER USER ge_monitor PASSWORD 'the_monitor_password'
    ```
    
    These passwords will be required when configuring Develocity to connect to the database.
    

<a id="stop_app_leave_db_up"></a>

## Appendix C: Stopping the Develocity application while leaving its embedded database running

This is done to ensure that data such as user access keys and manually defined roles, Build Cache node registrations and topology, and Test Distribution agent pools do not have changes which are lost when switching databases.

<a id="helm-based-installations"></a>

### Helm-based installations

*   Run the following commands:
    
    ```shell
    kubectl --namespace=«your-namespace» scale --replicas=0 deployment/gradle-enterprise-app
    kubectl --namespace=«your-namespace» scale --replicas=0 deployment/gradle-keycloak
    ```
    
    Or, for an OpenShift install:
    
    ```shell
    oc scale --replicas=0 deployment/gradle-enterprise-app
    oc scale --replicas=0 deployment/gradle-keycloak
    ```
    

<a id="legacy-before-2023-3-version"></a>

### (Legacy) Before 2023.3 version

*   Run the following commands:
    
    ```shell
    kubectl --namespace=«your-namespace» scale --replicas=0 statefulset/gradle-enterprise-app
    kubectl --namespace=«your-namespace» scale --replicas=0 statefulset/gradle-keycloak
    ```
    
    Or, for an OpenShift install:
    
    ```shell
    oc scale --replicas=0 statefulset/gradle-enterprise-app
    oc scale --replicas=0 statefulset/gradle-keycloak
    ```
    

<a id="run_migration_script"></a>

## Appendix D: Running the database migration script

<a id="steps-7"></a>

### Steps

1.  Download the database script bundle from [the appendix](#database_setup_download).
    
2.  Run the migration script:
    
    ```shell
    DESTINATION_PASSWORD="xxx" ./migrate-from-embedded.sh --installation-type=<kubernetes|openshift> --destination-host=my-host.db.com
    ```
    

Run the script without arguments to see full options (e.g. different username, non-default port etc). . Verify that the script terminates with a `Database migration complete` message

If any errors occur, it is recommended to drop and recreate your database, then restart from the first steps of your chosen strategy.

<a id="configure_ge_to_connect_to_new_database"></a>

## Appendix E: Configuring a Develocity instance to connect to your new database

While following one of the above strategies, you will at some stage need to configure a Develocity instance to connect to your new database. This may be your original instance, or another instance, depending on which migration strategy you take.

<a id="for-helm-based-installations"></a>

### For Helm-based installations

To configure an existing Helm-based Develocity installation (either standalone or Kubernetes) to connect to your new database, you need to run `helm upgrade` for your installation, using updated Helm values. In particular, the new values need to specify that Develocity should connect to your new database, as described in the [Standalone](https://docs.gradle.com/develocity/2025.3/reference/standalone-chart/#database_type) and [Kubernetes](https://docs.gradle.com/develocity/2025.3/reference/kubernetes-chart/#database_type) chart manuals.

When you’ve prepared the values you’re going to use, you should run helm to apply your updated configuration as described in the [Standalone](https://docs.gradle.com/develocity/2025.3/reference/standalone-chart/#changing_configuration_values) and [Kubernetes](https://docs.gradle.com/develocity/2025.3/reference/kubernetes-chart/#changing_configuration_values) Helm chart configuration guides. This will result in Develocity being restarted.

<a id="smoke_test"></a>

## Appendix F: Smoke testing a Develocity instance

This involves running a normal build, pointed at your Develocity instance, and verifying that:

*   A Build Scan is published and appears as expected when its reported URL is visited.
    
*   The Build Cache was used if expected.
    
*   Test Distribution was used if expected.
    

There are a few ways to do this:

*   Typically, the best smoke test is just to alter one of your normal builds, changing the configured Develocity server URL, see the [Develocity Gradle Plugin User Manual](https://docs.gradle.com/develocity/gradle/4.4/gradle-plugin/#connecting_to_develocity) or the [Develocity Maven Extension User Manual](https://docs.gradle.com/develocity/maven/2.4/maven-extension/#set_the_location_of_your_develocity_instance).
    
*   Alternatively, there are also the [Gradle Build Scan quickstart](https://github.com/gradle/gradle-build-scan-quickstart) and [Maven Build Scan quickstart](https://github.com/gradle/maven-build-scan-quickstart) projects that could be used. Configure these to point to the instance to be smoke tested using the instructions at the above user manual links.
    

<a id="pre_promotion"></a>

## Appendix G: Pre-promotion steps

The aim here is to ensure that builds can be converted to use a new instance as fast as possible. The specific steps will vary, depending on your infrastructure and promotion strategy. Some suggested steps for known setups:

*   If your promotion strategy involves updating DNS records, you should ensure that these have a small time-to-live (TTL) ahead of time. For example, if your DNS entries usually have a TTL of 24h, you should lower this to a short TTL a day ahead of the migration, to allow time for the entries with the longer TTL to expire from DNS caches in your infrastructure.
    
*   If your promotion strategy requires other staff in your organization to perform changes, for example, to update DNS records or change reverse proxy or other network settings, it’s recommended to schedule a time to perform the critical parts of the migration to ensure that they’re available to perform a switchover at the appropriate moment.
    
*   If your promotion strategy involves updating build configuration, it’s recommended to have a checklist of builds that need to be updated. If your code infrastructure supports it, having pull requests or equivalent for each case ready to go can reduce the effective downtime that builds will experience.
    

<a id="pre_copying"></a>

## Appendix H: Build Scan pre-copy verification steps

`develocityctl` is the CLI tool for interacting with Develocity installations. It has its own [user manual](https://docs.gradle.com/develocity/develocityctl/1.22/).

It operates by copying Build Scan data from one Develocity server to another. To do this, it needs network access to both servers, and access keys if necessary.

Steps:

*   Choose a host to run `develocityctl` on that will be able to access the normal URL of each server involved. This may be the host of one of the Develocity instances - if both would work, it is recommended to use the server of the source installation (for example, the installation that Build Scans will be copied from), to minimise the additional load on the production server.
    
*   Verify that both instances are accessible from the host that you will run `develocityctl` on. This can be done in various ways, but typically a tool like `curl` is available to do it:
    
    ```shell
    curl https://source.develocity.example.com/info/version
    curl https://destination.develocity.example.com/info/version
    ```
    
    If you can’t connect to either server, either discuss your network setup with an appropriate administrator or try another host.
    
*   To copy Build Scan data, `` develocityctl` `` requires Develocity access keys if the equivalent Build Scan operations would require them. This means that it needs an access key for a user with Build Scan publishing permissions if anonymous access to publish Build Scans is disabled on the destination server. See the [administration manual’s "Authenticated build access" section](https://docs.gradle.com/develocity/2025.3/administration/admin-manual/#authenticated_build_access). It also will need an access key with “Build data export” permissions if this permission is not granted to anonymous users on the source server, see the [Export API manual](https://docs.gradle.com/develocity/2025.3/reference/export-api/#access_control).
    
*   `develocityctl` can be run as a Java executable JAR file or as a Docker container.
    
    *   If running as a JAR, ensure that you have a JDK 21 compatible Java runtime installed, download the latest version from [the downloads section of the user manual](https://docs.gradle.com/develocity/develocityctl/1.22/) and verify that it works by running it using:
        
        ```shell
        java -jar develocityctl-«version».jar
        ```
        
    *   If running as a Docker container, verify that it can be pulled and run using:
        
        ```shell
        docker run --rm gradle/develocityctl:latest
        ```
        
    

<a id="develocityctl"></a>

## Appendix I: Running `develocityctl` to copy Build Scans

Assuming that you have run through the [pre-copy verification steps](#pre_copying), using `develocityctl` to copy Build Scans can be done by following the instructions below.

Ensure that your system has at least 2GB of memory available.

<a id="access-keys"></a>

### Access keys

If your destination servers require access keys, `export` the following environment variables before running `develocityctl`:

*   `SOURCE_ACCESS_KEY` for an access key with export permissions from the source server
    
*   `DESTINATION_ACCESS_KEY` for an access key with Build Scan publish permissions from the destination server
    

<a id="docker"></a>

### Docker

Run as a Docker container, optionally providing the access key environmental variables if appropriate:

```shell
docker run \
  --detach \
  --name=develocityctl \
  -e SOURCE_ACCESS_KEY \
  -e DESTINATION_ACCESS_KEY \
  gradle/develocityctl:latest build-scan copy \
  --sourceUrl=https://source.develocity.example.com/ \
  --destinationUrl=https://destination.develocity.example.com/
```

To follow progress, check the output in the Docker logs:

```shell
docker logs --follow develocityctl
```

`develocityctl` will write a file containing IDs of Build Scans that it was unable to copy to a file in the current directory.

This file can be retrieved from the container from its `/home` directory. The default filename is `failures.txt`, though this can be changed via a command line argument.

```shell
docker cp develocityctl:/home/failures.txt ./failures.txt
```

To instead have this file written to your local filesystem automatically, mount a local directory to the `/home` directory inside the container. For example:

```shell
mkdir ~/copy-failures

docker run \
  --detach \
  -v ~/copy-failures:/home \
  --name=develocityctl \
  gradle/develocityctl:latest build-scan copy \
  --sourceUrl=https://source.develocity.example.com/ \
  --destinationUrl=https://destination.develocity.example.com/
```

<a id="executable-jar"></a>

### Executable JAR

`develocityctl` requires a Java 21+ runtime to be installed, as described in the [user manual](https://docs.gradle.com/develocity/develocityctl/1.22/).

Run it with the following command:

```shell
java -Xms1024m -Xmx1024m -XX:MaxDirectMemorySize=512m \
  -jar develocityctl-«version».jar \
  build-scan copy \
  --sourceUrl=https://source.develocity.example.com/ \
  --destinationUrl=https://destination.develocity.example.com/
```

As the tool is expected to run for a significant amount of time, it’s recommended to detach it from the terminal and examine progress via logs:

```shell
nohup \
  java -Xms1024m -Xmx1024m -XX:MaxDirectMemorySize=512m \
  -jar develocityctl-«version».jar \
  build-scan copy \
  --sourceUrl=https://source.develocity.example.com/ \
  --destinationUrl=https://destination.develocity.example.com/
  >> develocityctl.log 2>&1 \
  & disown

tail -f develocityctl.log
```

<a id="additional-arguments"></a>

### Additional arguments

There are a few other command line arguments that the tool accepts - run it with `java -jar develocityctl-«version».jar build-scan copy --help` to see them all.

The most commonly used is `--copyScanDataSince`, which allows specifying a date beyond which only Build Scan ids should be copied, not the data itself. This effectively simulates the normal time-based retention window of Develocity’s [disk space management](https://docs.gradle.com/develocity/2025.3/administration/admin-manual/). Scans copied whose date was after the given date will be copied in full; older Build Scans will be copied such that if they are visited in the Develocity UI, the user will be informed that the Build Scan has been deleted.

<a id="restarting-develocityctl"></a>

### Restarting Develocityctl

`develocityctl` may need to be restarted if interrupted.

Typically, the process is:

*   Examine the logs from the last run and identify the last successfully copied Build Scan
    
*   If running as a Docker container, remove the old container using `docker stop` and `docker rm`
    
*   Rerun with an additional argument, `--startWithBuildId=«build-scan-id»` - the tool will resume copying Build Scans, starting with the next oldest after the one specified and working backwards chronologically from there.
    

Note that it’s safe to rerun `develocityctl` with a range of Build Scans to copy which overlaps with that of a previous run. Build Scans that have been previously copied will be detected and reported, and `develocityctl` will continue to copy other Build Scans.

<a id="data_cleanup"></a>

## Appendix J: Cleaning up the data directory or persistent volume

Once you are happy that the new database has all the data that you wanted migrated and the system is operational, you may want to remove the old data, and potentially remove attached storage.

For standalone installations, the data is typically in a `data/postgresql` subdirectory of the installation directory. For example, if using the default `/opt/gradle` installation directory, the database directory is `/opt/gradle/data/postgresql`. This directory can be safely deleted once the new setup is fully operational.

For Kubernetes installations, the associated PersistentVolumeClaim is called `gradle-database-volume` and can be deleted using the following commands:

```shell
kubectl --namespace=«your-namespace» delete --ignore-not-found=true pvc/gradle-database-volume
```

Or, for an OpenShift install:

```shell
oc delete --ignore-not-found=true pvc/gradle-database-volume
```

Depending on your reclaim policy, you may need to perform other manual steps to reclaim the space used. See the [Kubernetes documentation](https://kubernetes.io/docs/concepts/storage/persistent-volumes/#reclaiming) for more details.

<a id="backup_history_logs"></a>

## Appendix K: Reading the backup history logs

Warning: following procedure applies only for versions prior 2023.3.

In order to get an idea of your potential downtime during a backup and restore, it’s useful to be able to read the backup history for your existing embedded database.

A history of backups for your instance is recorded in a log file, accessible from the `database` pod’s ``database-tasks container, under the path `/opt/gradle/data/logs/backups-history.log``.

To access it, you need to first use `kubectl` (or `oc` for OpenShift installations) to get the name of the database Pod:

```shell
kubectl --namespace <your namespace> get pods --selector=app.kubernetes.io/part-of=gradle-enterprise --selector=app.kubernetes.io/component=database -o jsonpath='{.items[*].metadata.name}'
```

**Output:**

```
gradle-database-5b75f7f9d9-t6knf
```

With the name of the database Pod, you can print out the contents of the backup-history.log to see how long your backups usually take:

```shell
kubectl --namespace <your namespace> exec gradle-database-5b75f7f9d9-t6knf -c database-tasks -- tail /opt/gradle/data/logs/backups-history.log
```

**Output:**

```
2022-07-14 04:07:10 - Backup started
2022-07-14 04:09:23 - Backup completed
```

In this example, the logs indicate that the backup took ~2 hours.

<a id="upgrading_postgresql"></a>

## Appendix L: Upgrading your user-managed PostgreSQL database for Develocity

Develocity supports using a user-managed database [up to PostgreSQL 17](#postgresql_version_compatibility). If your Develocity instance is using a database instance of an earlier version, you may want to upgrade to a newer version to benefit from improvements in PostgreSQL.

<a id="upgrading_postgresql_steps"></a>

### Steps

1.  Download the database script bundle from [the appendix](#database_setup_download).
    
2.  Stop Develocity.
    
3.  Run the `prepare-upgrade.sh` script from the database script bundle, which removes database objects that are incompatible with a PostgreSQL upgrade. These objects will be recreated later by the database setup scripts.
    
    ```
    PGPASSWORD="xxx" ./prepare-upgrade.sh --host=my-host.db.com
    ```
    
4.  Upgrade the PostgreSQL database. This may be done using tools provided by a vendor if you are using a managed PostgreSQL service, or it may be something you do yourself by other means if you manage your user-managed database directly.
    
5.  (Do this step only if you run the database setup scripts manually i.e. you don’t configure Develocity to be able to connect to the database as a superuser or pseudo-superuser) Run the database setup scripts on the upgraded database.
    
6.  Start Develocity and confirm that it’s working.
    

If you have any questions or need any assistance don’t hesitate to get in touch with the Develocity support team or your customer success representative.

<a id="database_setup_download"></a>

## Appendix M: Database setup scripts

**2025.3** — *   [Download Database Setup Scripts](https://docs.gradle.com/downloads/gradle-enterprise-database-setup-zip/gradle-enterprise-database-setup-zip-2025.3.zip)
    
*   [Download SHA256 Checksum](https://docs.gradle.com/downloads/gradle-enterprise-database-setup-zip/gradle-enterprise-database-setup-zip-2025.3.zip.sha256)

> [!NOTE]
> Looking for an older version? You can find downloads for previous releases in our legacy documentation archive.