Deep-dive on the Next Gen Platform. Join the Webinar!

Skip Navigation
Show nav
Dev Center
  • Get Started
  • Documentation
  • Changelog
  • Search
  • Get Started
    • Node.js
    • Ruby on Rails
    • Ruby
    • Python
    • Java
    • PHP
    • Go
    • Scala
    • Clojure
    • .NET
  • Documentation
  • Changelog
  • More
    Additional Resources
    • Home
    • Elements
    • Products
    • Pricing
    • Careers
    • Help
    • Status
    • Events
    • Podcasts
    • Compliance Center
    Heroku Blog

    Heroku Blog

    Find out what's new with Heroku on our blog.

    Visit Blog
  • Log inorSign up
Hide categories

Categories

  • Heroku Architecture
    • Compute (Dynos)
      • Dyno Management
      • Dyno Concepts
      • Dyno Behavior
      • Dyno Reference
      • Dyno Troubleshooting
    • Stacks (operating system images)
    • Networking & DNS
    • Platform Policies
    • Platform Principles
  • Developer Tools
    • Command Line
    • Heroku VS Code Extension
  • Deployment
    • Deploying with Git
    • Deploying with Docker
    • Deployment Integrations
  • Continuous Delivery & Integration (Heroku Flow)
    • Continuous Integration
  • Language Support
    • Node.js
      • Working with Node.js
      • Troubleshooting Node.js Apps
      • Node.js Behavior in Heroku
    • Ruby
      • Rails Support
      • Working with Bundler
      • Working with Ruby
      • Ruby Behavior in Heroku
      • Troubleshooting Ruby Apps
    • Python
      • Working with Python
      • Background Jobs in Python
      • Python Behavior in Heroku
      • Working with Django
    • Java
      • Java Behavior in Heroku
      • Working with Java
      • Working with Maven
      • Working with Spring Boot
      • Troubleshooting Java Apps
    • PHP
      • PHP Behavior in Heroku
      • Working with PHP
    • Go
      • Go Dependency Management
    • Scala
    • Clojure
    • .NET
      • Working with .NET
  • Databases & Data Management
    • Heroku Postgres
      • Postgres Basics
      • Postgres Getting Started
      • Postgres Performance
      • Postgres Data Transfer & Preservation
      • Postgres Availability
      • Postgres Special Topics
      • Migrating to Heroku Postgres
    • Heroku Key-Value Store
    • Apache Kafka on Heroku
    • Other Data Stores
  • AI
    • Working with AI
  • Monitoring & Metrics
    • Logging
  • App Performance
  • Add-ons
    • All Add-ons
  • Collaboration
  • Security
    • App Security
    • Identities & Authentication
      • Single Sign-on (SSO)
    • Private Spaces
      • Infrastructure Networking
    • Compliance
  • Heroku Enterprise
    • Enterprise Accounts
    • Enterprise Teams
    • Heroku Connect (Salesforce sync)
      • Heroku Connect Administration
      • Heroku Connect Reference
      • Heroku Connect Troubleshooting
  • Patterns & Best Practices
  • Extending Heroku
    • Platform API
    • App Webhooks
    • Heroku Labs
    • Building Add-ons
      • Add-on Development Tasks
      • Add-on APIs
      • Add-on Guidelines & Requirements
    • Building CLI Plugins
    • Developing Buildpacks
    • Dev Center
  • Accounts & Billing
  • Troubleshooting & Support
  • Integrating with Salesforce
  • Heroku Architecture
  • Migrating an Application to Another Region

Migrating an Application to Another Region

English — 日本語に切り替える

Last updated February 12, 2025

Table of Contents

  • Heroku CLI
  • Process
  • Fork application
  • Manual add-on configuration
  • Verification
  • DNS preparation
  • Database preparation
  • Maintenance mode
  • Switchover database
  • Add-on data
  • Scale dynos
  • Custom domains
  • DNS
  • Update git remotes
  • Forked app state

Follow the steps outlined in this article to copy all add-on services, config vars, and Heroku Postgres data to a new app in the other region and migrate live traffic to the new app.

Heroku CLI

You must have the Heroku CLI installed to use the features described here. Verify your CLI installation and update it to the latest version with heroku update.

Process

In this guide, sourceapp is the original (source) app and targetapp is the migrated (target) app.

Before beginning an app migration, please understand the proposed process as well as any nuances that are specific to your application. The following is the recommended migration approach.

Verification phase

  • Use heroku fork to create targetapp as a fork of sourceapp
  • Verify targetapp add-on provisioning and config vars.

Cut-over live traffic

  • Prepare DNS and data for migration
  • Put sourceapp in maintenance mode
  • Migrate production data
  • Move custom domains from sourceapp to targetapp
  • Adjust DNS settings to point to targetapp
  • Finalize targetapp setup

Fork application

Begin the verification phase by forking the application to create a copy in another region, for example the eu region. This will copy all Heroku Postgres data and config vars and will re-provision all add-ons. Depending on the size of your database this process may take some time.

Only Heroku Postgres data is automatically copied to the new application. All other add-ons are simply re-provisioned. Please consider the ramifications of this approach and plan for proper data migration with any other applicable add-ons.

Forking

The heroku fork command is no longer included with the Heroku CLI by default, but it is available via a plugin with the following command:

heroku plugins:install heroku-fork

With this installed the following command will be available:

heroku fork forks sourceapp to a new targetapp. targetapp should not exist prior to the fork command.

$ heroku fork --from sourceapp --to targetapp --region eu
Creating fork targetapp... done
Copying slug... done
Adding heroku-postgresql:essential-0... done
Creating database backup from sourceapp... .. done
Restoring database backup to targetapp... .. done
Copying config vars... done
Fork complete, view it at http://targetapp-1234567890ab.herokuapp.com/

Conversely, use --region us if your app is in the eu region and you are migrating to us region.

Provision failures

When forking to a different region than sourceapp some add-ons may fail provisioning if they’re not available in the new region or are outdated plans.

$ heroku fork --from sourceapp --to targetapp --region eu
Creating fork targetapp... done
Copying slug... ........ done
Adding airbrake:developer... done
Adding bonsai:test... skipped (not found)
Adding komrade:test... skipped (This app is in region eu, komrade:test is only available region us)
...

If the add-ons can’t be provisioned because the original plan no longer exists, upgrade the plan on the source app to ensure a seamless migration.

$ heroku addons:upgrade memcachier:dev -a sourceapp
Upgrading to memcachier:dev on sourceapp... done, v207 (free)

If the add-on is not yet available in the new region consider using another provider of that service that does have availability in your app’s region.

Re-run the fork command until it succeeds without error. Prior to each run make sure incomplete provisions of targetapp are destroyed.

$ heroku apps:destroy -a targetapp

Manual add-on configuration

There are some add-ons that require additional configuration after provisioning. There may be others beyond the add-ons listed below so please review your app’s add-ons for any that require manual configuration steps.

Scheduler

The Heroku Scheduler add-on requires that the job schedule be manually transferred. Open the scheduler dashboard for both sourceapp and targetapp side-by-side to view the diffs and manually copy the jobs.

$ heroku addons:open scheduler -a sourceapp
$ heroku addons:open scheduler -a targetapp

Verification

Once forking has completed and all add-on configuration has been duplicated, open the forked application to verify it’s functioning properly before proceeding with the final migration steps.

$ heroku open -a targetapp

If your app uses OAuth, or any other domain-specific external service, you may have to provision a new service for use during this verification phase when the domain is not the same as your production setup.

Once your forked app has been verified to be functioning properly you can begin the cut-over process.

DNS preparation

Apps with custom domains should manually adjust their DNS settings as opposed to performing an app rename or using a DNS add-on. These alternatives are either not supported or incur non-trivial downtime.

If your app has custom domains, you should lower the TTL for each of them with your DNS provider to a low value, such as 60 or 120 seconds. This minimizes the amount of downtime that results from changing your records during the migration process and allows you to quickly correct any DNS related errors.

To ensure that all DNS caches are updated with the new TTL, you should wait at least as long as the previous TTL before proceeding with the migration.

Database preparation

Although the app-forking process creates a new database, it’s only used to verify the new app’s setup. The actual database migration should occur only when the sourceapp is in maintenance mode (to avoid data being written during the migration) and should be done in a way that minimizes application downtime.

If you have a Standard-tier or higher database, you can provision a follower in advance and wait until it is up-to-date with the master database before cutting over apps. (Development tier database users can bypass this step as their database migration will occur completely during the cut-over phase).

Create follower

Provision a new database (of the same plan) on targetapp to follow the current database on sourceapp.

The addons:create example follows the syntax for Heroku CLI v9.0.0 or later. If you’re on v8.11.5 or earlier, use the command:

$ heroku addons:create heroku-postgresql:standard-0 -a targetapp --follow $(heroku config:get DATABASE_URL -a sourceapp)
$ heroku addons:create heroku-postgresql:standard-0 -a targetapp -- --follow $(heroku config:get DATABASE_URL -a sourceapp)
Adding heroku-postgresql:standard-0 on targetapp... done, v32 ($50/mo)
Attached as HEROKU_POSTGRESQL_CHARCOAL_URL
Follower will become available for read-only queries when up-to-date
Use `heroku pg:wait` to track status.

$ heroku pg:wait -a targetapp
Waiting for database HEROKU_POSTGRESQL_CHARCOAL_URL... / available

After the follower has become available it may take some time for it to receive all the data from the source database. Use the pg:info command to view how many commits behind the follower is from the source database.

$ heroku pg:info -a targetapp
=== HEROKU_POSTGRESQL_CHARCOAL_URL
Plan:        Standard 0
Status:      available
Region:      eu-west-1
...
Behind By:   47980 commits

Only when the follower is, at most, a few hundred commits behind should you begin the application migration.

Maintenance mode

To ensure that no data modification occurs during the migration process, sourceapp should be put in maintenance mode.

From this point forward the source application will be inaccessible to your users. Only when the app has been migrated and all DNS propagation complete will the target app be accessible. Please plan for this downtime appropriately.

$ heroku maintenance:on -a sourceapp
Enabling maintenance mode for sourceapp... done

Switchover database

With the sourceapp in maintenance mode it’s now safe to migrate data to targetapp. The approach you take here depends on your Heroku Postgres database tier.

Standard-Tier or Higher Databases

If you have a Standard-tier or higher database and have created a follower database on targetapp, wait until it is fully caught up (0 commits behind) and promote it to be the master.

$ heroku pg:info -a targetapp
=== HEROKU_POSTGRESQL_CHARCOAL_URL
Plan:        Standard 0
Status:      available
Location:    eu-west-1
...
Behind By:   0 commits

$ heroku pg:unfollow -a targetapp HEROKU_POSTGRESQL_CHARCOAL_URL
Unfollowing HEROKU_POSTGRESQL_CHARCOAL_URL... done

$ heroku pg:promote -a targetapp HEROKU_POSTGRESQL_CHARCOAL_URL
Promoting HEROKU_POSTGRESQL_CHARCOAL_URL to DATABASE_URL... done

The follower database is now the primary database for targetapp and its location has been copied to the DATABASE_URL config var.

PG Backups

If you are using an Essential-tier database, you must use PG Backups to transfer your database. You can use pg:copy to transfer the database directly:

$ heroku pg:copy sourceapp::DATABASE_URL DATABASE_URL -a targetapp

This process can take some time depending on the size of your database.

Add-on data

Other add-on providers may have a different procedure for migration, or no migration functionality at all. Whether the data needs to be migrated is a question of how you’re using that add-on. Please see the documentation for your add-on providers for more information.

Scale dynos

Using heroku ps to examine your dynos, copy the dyno formation from sourceapp to targetapp.

$ heroku ps -a sourceapp
=== web: `bundle exec thin start -p $PORT`
web.1: up 2013/02/12 18:56:17 (~ 20h ago)
web.2: up 2013/02/12 19:14:45 (~ 19h ago)

$ heroku scale web=2 -a targetapp

Check your logs to ensure the dynos started properly.

$ heroku logs -t -n 1000 -a targetapp

Custom domains

For targetapp to receive user activity, Heroku must know which domain is served by your app. List the custom domains on the old app:

$ heroku domains -a sourceapp
=== sourceapp Domain Names
www.example.com

For each of these domains, remove them from the sourceapp and add them to targetapp.

$ heroku domains:remove -a sourceapp www.example.com
Removing www.example.com from sourceapp... done

$ heroku domains:add -a targetapp www.example.com
Adding www.example.com to targetapp... done

DNS

To route traffic to your new app, adjust the DNS settings so any custom domains resolve to targetapp. Add the following CNAME record in your DNS provider’s control panel.

Type Name Target
CNAME www targetapp-1234567890ab.herokuapp.com

A-records are not supported. If required, use a DNS-level redirect or ALIAS record to resolve the root domain to targetapp-1234567890ab.herokuapp.com.

Propagation

If you’ve adjusted your DNS TTL to a low value it shouldn’t take more than a few minutes for requests to be routed to targetapp. Inspect the logs on targetapp to verify that requests are properly resolved and handled.

$ heroku logs -t -a targetapp

Once the DNS changes propagate all requests to your custom domain should be served by the new EU location.

Update git remotes

Forking your application doesn’t automatically create a new git remote in your current project. To deploy to targetapp you will need to establish the git remote yourself. Use heroku info to retrieve the Git URL of the new application and the set it manually.

$ heroku info -a targetapp
=== targetapp
...
Git URL:       git@heroku.com:targetapp.git
...

$ git remote add forked git@heroku.com:targetapp.git

In this example, targetapp‘s git remote is named forked. Deploy to this app with:

$ git push forked master

If you wish to make the new app the default deployment target (after migration) you can rename the git remotes.

$ git remote rename heroku old
$ git remote rename forked heroku

targetapp is now the default deployment target for all future deploys. After a reasonable period of time, be sure to de-provision any unused resources on sourceapp.

Forked app state

Forked apps are as close to the source app as possible. However, there are some differences.

Collaborators

No users from the source app are transferred over to the forked app. You need to add collaborators yourself.

$ heroku access:add colleague@example.com -a targetapp

Labs features

Any enabled Heroku Labs features on sourceapp are not re-enabled on targetapp. You will need to re-enable these yourself.

Keep reading

  • Heroku Architecture

Feedback

Log in to submit feedback.

The Procfile Regions

Information & Support

  • Getting Started
  • Documentation
  • Changelog
  • Compliance Center
  • Training & Education
  • Blog
  • Support Channels
  • Status

Language Reference

  • Node.js
  • Ruby
  • Java
  • PHP
  • Python
  • Go
  • Scala
  • Clojure
  • .NET

Other Resources

  • Careers
  • Elements
  • Products
  • Pricing
  • RSS
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku Blog
    • Heroku News Blog
    • Heroku Engineering Blog
  • Twitter
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku
    • Heroku Status
  • Github
  • LinkedIn
  • © 2025 Salesforce, Inc. All rights reserved. Various trademarks held by their respective owners. Salesforce Tower, 415 Mission Street, 3rd Floor, San Francisco, CA 94105, United States
  • heroku.com
  • Legal
  • Terms of Service
  • Privacy Information
  • Responsible Disclosure
  • Trust
  • Contact
  • Cookie Preferences
  • Your Privacy Choices