Tip
As you follow this guide, you can refer to the Enterprise Live Migrations CLI reference for more detailed usage information. If you encounter errors, see Troubleshooting live migrations from GitHub Enterprise Server to GHE.com.
Prerequisites
Make sure your environments and developers are ready for the migration. See Preparing for your live migration from GitHub Enterprise Server to GHE.com.
1. Configure GitHub Enterprise Server
You must set some configuration on the GitHub Enterprise Server instance before creating tokens and performing a migration. These configuration values apply to all ELM migrations. Developers on GitHub Enterprise Server may experience a brief downtime when you apply the new configuration.
-
Access the GitHub Enterprise Server administrative shell over SSH. See Accessing the administrative shell (SSH).
-
Set the following configuration variables with
ghe-config.For example:
ghe-config app.elm-exporter.enabled trueVariable Set this to... app.elm-exporter.enabledtrueapp.elm.internal-webhooks-enabledtrueapp.elm-exporter.webhooks-loopback-address-enabledtruesecrets.elm-exporter.migration-target-urlThe API URL for your destination enterprise (for example: https:/). Do not include a trailing slash at the end of the URL./ api.octocorp.ghe.com secrets.elm-exporter.source-userThe username associated with the operator's GitHub Enterprise Server token. This should be your username on GitHub Enterprise Server; if someone else is going to create this token, the value here should be set to their username. We recommend the ghe-adminuser. -
Apply the configuration.
Shell ghe-config-apply
ghe-config-apply -
Leave the SSH session. You will run the rest of the commands in a local terminal session.
2. Create operator tokens with enterprise access
The operator must authenticate to both the source and destination enterprise with a personal access token (classic). For instructions on creating tokens, see Managing your personal access tokens.
Ensure that you make a note of both tokens, as you will need them in the next step.
-
On GitHub Enterprise Server, create a personal access token (classic) and select the required scope:
admin:enterprise
You will use this token as the Source token when configuring the ELM CLI.
-
On GHE.com, create a personal access token (classic) and select the required scopes:
admin:enterpriseadmin:org
You will use this token as the Target token when configuring the ELM CLI.
3. Configure the ELM command line tool
You will run the migration from a local terminal session, using an extension of the GitHub CLI.
-
Install the GitHub CLI on your local machine. You must be using version 2.0 or later.
-
Install the ELM extension.
Shell gh extension install github/gh-elm
gh extension install github/gh-elm -
Launch the installation wizard to configure the extension.
Shell gh elm configure
gh elm configure -
Follow the instructions in the installation wizard, providing the API URLs (for example:
https://api.SUBDOMAIN.ghe.com) for your source and destination and the tokens you created in the previous step.
Any of these values can also be provided as CLI flags on any gh elm command, which will take priority over the configuration. For example: --target-url https://api.SUBDOMAIN.ghe.com.
This setup process will store the URLs in a platform-specific configuration file in your operating system's configuration directory, at gh-elm/config.json. The access tokens will be securely stored in your computer's secret storage.
4. Configure the live migration secrets
In addition to the operator tokens with enterprise access, you must create a personal access token (classic) for the source and target organizations. You must repeat these steps for every organization you are migrating from.
Create access tokens
ELM must authenticate with a personal access token (classic) for both the source and destination of the migration. For instructions on creating tokens, see Managing your personal access tokens.
Ensure that you make a note of these tokens, as you will need them in the next step.
-
Create a personal access token (classic) on GitHub Enterprise Server with the following scopes:
repoadmin:orgadmin:repo_hookadmin:org_hook
This is your source token.
-
Create a personal access token (classic) on GHE.com with the following scopes:
repoworkflowadmin:orgadmin:repo_hookadmin:enterprise
This is your target token.
Important
If single sign-on is enforced on the target organization on GHE.com, you must authorize the GHE.com token for SSO.
Configure your organization's ELM secrets
Use the gh elm config commands to set the source and target access tokens:
-
Set the source token.
Shell gh elm config set-source-pat EXISTING-GHES-ORG
gh elm config set-source-pat EXISTING-GHES-ORGPaste the source token into the terminal when asked.
-
Set the target token.
Shell gh elm config set-target-pat EXISTING-GHES-ORG
gh elm config set-target-pat EXISTING-GHES-ORGPaste the target token into the terminal when asked.
You can also set the tokens interactively, using gh elm config org-tokens EXISTING-GHES-ORG, or in your organization settings at https://GHES_HOSTNAME/organizations/EXISTING-GHES-ORG/settings/secrets/elm-exporter/.
5. Create a migration
Create a new migration by specifying the source and target repository details.
Note
The target-org can be new or existing. If the target organization doesn't already exist, it will be created during the migration. However, no settings from the source organization will be migrated.
gh elm migration create \ --source-org EXISTING-GHES-ORG \ --source-repo EXISTING-GHES-REPO \ --target-org GHEC-ORG \ --target-repo NEW-GHEC-REPO
gh elm migration create \
--source-org EXISTING-GHES-ORG \
--source-repo EXISTING-GHES-REPO \
--target-org GHEC-ORG \
--target-repo NEW-GHEC-REPO
For example:
gh elm migration create \
--source-org my-ghes-org \
--source-repo my-ghes-repo \
--target-org my-dr-org \
--target-repo my-dr-repo
Optional flags:
--start: If you're ready to start the migration immediately.--target-visibility: Migrated repositories are created with internal visibility by default, but you can specifyprivate.
Save the migration ID
You should see a response like the following:
{
"migrationId": "2b5c9eae-b5da-4306-ab04-2a29cc2b7cb9",
"expiresAt": "2026-02-11T21:49:33.619162159Z"
}
Export the migrationId as a variable, as you will need it for the next commands. For example:
export MIGRATION_ID='2b5c9eae-b5da-4306-ab04-2a29cc2b7cb9'
6. Start the migration
If you didn't already start the migration, start it now using the migration ID you just saved.
gh elm migration start --migration-id $MIGRATION_ID
gh elm migration start --migration-id $MIGRATION_ID
This launches the backfill and live update processes. ELM is now collecting data from the source repository and listening for supported webhook events.
7. Monitor the migration
When the migration has started, you should see a new repository on GHE.com. During the migration, you will see the repository fill with an initial load of data and receive updates as developers continue to work in the source repository.
You can monitor the progress of the migration interactively using the watch command:
gh elm migration watch $MIGRATION_ID
This will poll the migration status API and display a self-refreshing text UI that reflects the current progress.
Programmatic monitoring using migration status
If you want a migration status suitable for automation, use the status command:
gh elm migration status --migration-id $MIGRATION_ID
gh elm migration status --migration-id $MIGRATION_ID
The most important indicator in the response is the status in the combinedState object. When the status reaches COMBINED_STATUS_READY_FOR_CUTOVER, you should be ready to proceed to the next step. However, you will be alerted in the displayMessage if any individual resources failed to migrate, which you may need to investigate.
For example:
"combinedState": {
"status": "COMBINED_STATUS_READY_FOR_CUTOVER",
"displayMessage": "Ready for cutover (1 resources failed)",
"repositories": [
{
"repositoryNwo": "new-test-org/my-new-repo",
"phase": "REPOSITORY_PHASE_READY_FOR_CUTOVER",
"displayStatus": "Ready for cutover (1 failed)"
}
],
"readyForCutover": true,
"cutoverBlockers": []
},
Tips:
- If you're running multiple migrations, you can check the status of all of them with
gh elm migration list. This command shows in-progress migrations by default, but you can also filter by--status. - If you encounter failure statuses that require attention, see Troubleshooting live migrations from GitHub Enterprise Server to GHE.com.
8. Complete the migration
When a migration is ready for cutover, you can complete the migration. The cutover process will archive the source repository, making it permanently read-only unless a repository administrator unarchives it.
gh elm migration cutover --migration-id $MIGRATION_ID
gh elm migration cutover --migration-id $MIGRATION_ID
Continue to monitor the migration. When you see the MIGRATION_STATUS_COMPLETED status at the top of the response, the migration is complete, although there are some follow-up tasks to give access to users from GitHub Enterprise Server.
Next steps
Give users access to the new repository and reconcile activity with user accounts. See Completing your live migration from GitHub Enterprise Server to GHE.com.