How to migrate Azure API Management Developer portal to another APIM instance with Azure DevOps

Published by Peter KARDA
Category : API Management / Azure

The Azure API Management (APIM) Developer Portal is shipped with the default theme. Many customers change it to reflect the corporate branding and present the APIs in a custom way.

Technically the portal is based on the Paperbits framework which allows to redesign of the portal within the browser. The whole content is stored in a JSON file and the images are hosted on the internal blog storage of API Management.

In the real world, we often have multiple APIM environments which raises the question of how to migrate the portal from one to another environment. In this article, we’ll show how to migrate the APIM Developer Portal from one environment to another with Azure DevOps.

This article will show you how to create an Azure DevOps (YAML) pipeline and use the APIM Developer Portal tools to migrate the portal content.


Migration tools

Azure APIM Developer Portal is an open-source project that along with the portal files contains also the migration tools. Currently, there are two versions of the tools (v2 and v3) but in the article, we’ll use the last version which is located in the “scripts.v3” folder. The folder contains several Node.js scripts and batch files for the migration.


Migration process

Note that in the folder you can find migrate.js and migrate.bat files that enable to migrate of the portal with only one command. It worked well when I did the migration locally where my Azure account had enough permissions to proceed with the migration. However, in my Azure DevOps environment, I had only Service connections for the source and destination (target) subscriptions so the migration had to be done in another way. Instead of one migrate command we’ll use multiple commands that allow us to proceed with the migration step-by-step.

The commands we’ll need to execute in the order are:

  • capture – captures the content of the source Developer portal
  • cleanup – cleans-up the content of the destination Developer portal to avoid the conflicts
  • generate – generates the content for the destination Developer portal (replacing URLs,…)

Fair enough, let’s create an Azure DevOps pipeline with those commands to proceed with the migration.


Creating and configuring the Azure DevOps pipeline

Now let’s see how to create the YAML pipeline. As mentioned we need to execute three commands – capture, cleanup and generate. The pipeline has to capture the data from the source APIM Developer Portal, clean up the destination (portal) and generate content for the destination APIM Developer Portal. Recently a new option (–publish true) has been added to the generate command. With this option we can publish the portal right after the content is generated.

As the migration tools are implemented in NodeJs, the first task in the pipeline will be the installation of the Node.js JavaScript runtime.

The source code below contains the Azure DevOps pipeline (YAML). It will execute all the tasks necessary for the migration of the Azure API Management Developer portal from one APIM instance to another. I’ll explain all the pipeline variables later in the article.

name: APIM_DeveloperPortalMigration   
trigger: none
  location: northeurope
  sourceServiceConnection: <source_service_connection>
  destServiceConnection: <destination_service_connection>
  sourceSubscriptionId: <source_subscription_id>
  destSubscriptionId: <destination_subscription_id>
  sourceResourceGroupName: <source_apim_instance_resource_group>
  destResourceGroupName: <destination_apim_instnace_resource_group>
  sourceServiceName: <source_apim_instance_name>
  destServiceName: <destination_apim_instance_name>
  # All tasks on APIM Developer portal pipeline
  - job: Deploy_APIM_Developer_Portal
    displayName: Deploy APIM Developer portal from one APIM instance to another APIM instance Migration
      vmImage: ubuntu-latest
    timeoutInMinutes: 90
      - task: Npm@1
        displayName: Npm Install command
          command: "install"
          workingDir: 'portal/scripts.v3'
      - task: AzureCLI@2
        displayName: Capturing source portal
          azureSubscription: $(sourceServiceConnection)
          scriptType: 'pscore'
          workingDirectory: 'portal/scripts.v3'
          scriptLocation: 'inlineScript'
          inlineScript: 'node ./capture --subscriptionId $(sourceSubscriptionId) --resourceGroupName $(sourceResourceGroupName) --serviceName $(sourceServiceName)'
      - task: AzureCLI@2
        displayName: Cleaning up destination portal
          azureSubscription: $(destServiceConnection)
          scriptType: 'pscore'
          workingDirectory: 'portal/scripts.v3'
          scriptLocation: 'inlineScript'
          inlineScript: 'node ./cleanup --subscriptionId $(destSubscriptionId) --resourceGroupName $(destResourceGroupName) --serviceName $(destServiceName)'
      - task: AzureCLI@2
        displayName: Generating destination portal
          azureSubscription: $(destServiceConnection)
          scriptType: 'pscore'
          workingDirectory: 'portal/scripts.v3'
          scriptLocation: 'inlineScript'
        inlineScript: 'node ./generate --publish true --subscriptionId $(destSubscriptionId) --resourceGroupName $(destResourceGroupName) --serviceName $(destServiceName)'

Pipeline variables

To migrate the APIM Developer Portal from source to destination APIM instance the following  parameters (in angle brackets) should be specified:

<source_service_connection> – service connection in Azure DevOps allows accessing resources in the source subscription

<destination_service_connection> – service connection in Azure DevOps allowing to access resources in the destination subscription

<source_subscription_id> – subscription id of the source APIM instance

<destination_subscription_id> – subscription id of the destination APIM instance

<source_apim_instance_resource_group> – resource group name of the source APIM instance

<destination_apim_instnace_resource_group> – resource group name of the destination APIM instance

<source_apim_instance_name> – name of the source APIM instance

<destination_apim_instance_name> – name of the destination APIM instance


Preparing DevOps repository

Let’s prepare a workspace in the Azure DevOps repository. Firstly I’ve created a “portal” folder where we’ll keep all portal-related files and migration tools. I’ve cloned the APIM Developer portal GitHub repository to my local disk and the then I’ve copied the folder “scripts.v3” folder. After I’ve created my Azure DevOps YAML pipeline and pushed it to the portal folder. In the end, we will commit and push the files to the Azure DevOps repository so the structure on the Azure DevOps repository looks something like this:

APIM portal migration tools

After the files are in the Azure DevOps repository all you need to find the YAML pipeline file in the Azure DevOps and execute it. If everything is configured correctly and the service connections have sufficient permissions, the portal content will be migrated between the Azure APIM instances.


One step further

It might happen that the destination portal should use the different URLs (custom domains) that are attributed by default to the APIM instance. In that case, we can add our pipeline one more task and call updatecontenturl command:

- task: AzureCLI@2
  displayName: Updating destination urls
    azureSubscription: $(destServiceConnection)
    scriptType: 'pscore'
    workingDirectory: 'portal/scripts.v3'
    scriptLocation: 'inlineScript'
    inlineScript: 'node ./updatecontenturl --subscriptionId $(destSubscriptionId) --resourceGroupName $(destResourceGroupName) --serviceName $(destServiceName) --existingEnvUrls $(existingEnvUrls) --destEnvUrls $(destEnvUrls)'

You’ll need to add two new variables to the variable list:

  • existingEnvUrls – one or more comma-separated existing URLs
  • destEnvUrls – one or more comma-separated destination URLs

If multiple URLs are specified the number and order of URLs must match the existing destination list.



That’s it. The last version of the tools has made migration easier. The migration commands are well documented in their source files so do not hesitate the check them.