Skip to main content
This guide explains how to migrate an existing application from another hosting provider to Upsun. It focuses on the technical steps required to make your application deployable on Upsun, including configuration, services, environment variables, and data migration. No prior experience with Upsun is needed — each step is explained simply, with examples and troubleshooting tips.

Before you begin

You need:
  • An understanding of the main Upsun concepts
  • A Upsun account. If you don’t already have one, register for a trial account. You can sign up with an email address or an existing GitHub, Bitbucket, or Google account. If you choose one of these accounts, you can set a password for your Upsun account later.
  • The Upsun CLI installed locally
Follow the steps below to begin the migration of your project.

1. Audit your data from your current project

Before migrating, make sure you have access to:
  • Your source code
  • Your database
  • Your assets and uploaded files
Runtime & build
  • Runtime version: language and version in use (Node.js, Python, Ruby, PHP, etc.)
  • Package manager: npm, yarn, pnpm, pip, composer, bundler, etc.
  • System dependencies: packages installed via apt, yum, or similar
  • Build process: how assets are compiled, if any (webpack, vite, sass, etc.)
  • How the app starts: systemd unit, supervisor config, pm2, Docker entrypoint, etc.
  • Reverse proxy: nginx, Apache, or Caddy config (rewrites, headers, timeouts, SSL termination)
Processes & scheduling
  • Background workers: how they are started and supervised
  • Cron jobs: run crontab -l to list all scheduled tasks
Environment & secrets
  • Environment variables: run env on your server to list them
  • .env files: check for any local env files used at runtime
  • SSL certificates: Let’s Encrypt, manual certs, or managed by proxy
Data & storage
  • Database engine and version: PostgreSQL, MySQL, MongoDB, etc.
  • Writable folders: directories your app writes to at runtime (uploads, cache, logs)
  • Backup strategy: how and where backups are currently stored
Access
  • Users and teams: who currently has access to the server and application
  • SSH access: confirm you can connect to export data

How Upsun maps to your existing architecture

When migrating from another platform, map your existing components to Upsun concepts.
Existing platform conceptUpsun equivalent
Web dyno / serverApplication Container
Worker dynoWorker
Add-on databaseService
Environment variablesEnvironment variables
Upload storageMounts
Cron jobs / Heroku SchedulerCrons
DomainsRoutes
BuildpacksBuild hooks
Review apps / preview deploymentsPreview environments
SSL certificatesAutomatic TLS (managed)

2. Clone your Git repository locally

As a start, you need to clone your source code locally to make it Upsun ready.
git clone <REPOSITORY_URL> your-app-directory
cd your-app-directory

3. Initialize Upsun configuration

A Upsun project is configured through the .upsun/config.yaml file. This file defines your applications, services, routes, and runtime configuration. Upsun provides a CLI project:init command.
upsun project:init
This command initializes your Upsun project configuration. If you choose With AI (automatic), it detects your app’s requirements and creates a config file for you.

4. Create a new Upsun project

If you do not already have an organization created on Upsun, create one:
upsun org:create
Then run the following command to create a project:
upsun project:create
When prompted, fill in details like the project name, region, and the name of your organization.
Before migrating your production environment, we recommend pushing to a separate branch first. Upsun automatically creates a preview environment for each branch, allowing you to validate your configuration, services, and data before switching any production traffic.

5. Configure services and start commands

Configure your services

In your Upsun project, you can add as many services as you need. List your current services in use and add them in the configuration, following the corresponding Service page. As an example, if your current project is using PostgreSQL and Redis, edit your .upsun/config.yaml file and add the following:
.upsun/config.yaml
applications:
  myapp:
    relationships:
      database:
      cache:
services:
  database:
    type: postgresql:16
  cache:
    type: redis:7.2
You need to declare your services in the services top YAML key and add a relationships for each service in your myapp configuration. Service environment variables will be automatically injected in your myapp container to interact with.

Configure how your application and workers start

Find out how your current application is started and convert it to an Upsun configuration.
  • How you start your runtime should go in myapp.web.commands.start
  • How you start your worker should go in myapp.workers.<WORKER_NAME>.commands.start
Example:
.upsun/config.yaml
applications:
  myapp:
    type: "python:3.12"
    web:
      commands:
        start: "gunicorn app:app --workers 4 --bind 0.0.0.0:$PORT"
    workers:
      celery:
        commands:
          start: "celery -A tasks worker --loglevel=info"

6. Configure build and deploy hooks

If you have custom build steps, define them explicitly in the hooks.build and hooks.deploy section:
.upsun/config.yaml
applications:
  myapp:
    hooks:
      build: |
        pip install -r requirements.txt
        python manage.py collectstatic --noinput
      deploy: |
        python manage.py migrate --noinput
The app container is fully writable during the build hooks and is read-only during the deploy hooks. During the deploy hooks, only defined mounts are writable.

7. Define mounts

Define your mounts (writable folders) in .upsun/config.yaml:
.upsun/config.yaml
applications:
  myapp:
    mounts:
      'web/uploads':
        source: storage
        source_path: uploads
      'private':
        source: instance
        source_path: private
Refer to supported mount types for more information.

8. Define routes

If you are migrating a multi-application project, or want to customize how your application is served, you need to configure routes.

9. Optional: Define a resource initialization strategy

By default, when you first deploy your project, Upsun allocates default resources to each of your containers. If you don’t want to use those default resources, define your own resource initialization strategy before pushing your code. Alternatively, you can amend those default container resources after your project is deployed.

10. Optional: Add environment variables

If your app requires environment variables to build properly, add them to your environment. Extract existing environment variables from your project:
SSH to your server and use the env CLI command to list all your existing environment variables:
ssh <YOUR-SERVER-IP>
env
Review the variables and recreate them in Upsun using variable:create.
# Standard environment variables
upsun variable:create --level environment --name env:<VariableBlock name="KEY" /> --value <VariableBlock name="VALUE" />

# Project-wide variables
upsun variable:create --level project --name env:<VariableBlock name="KEY" /> --value <VariableBlock name="VALUE" />

# Application-specific variables
upsun variable:create --app-scope myapp --name env:<VariableBlock name="KEY" /> --value <VariableBlock name="VALUE" />
For sensitive values, be sure to add the --sensitive true option to avoid exposing any confidential information.

11. Push your changes

The way to push your code to Upsun depends on whether you’re hosting your code with a third-party service using a source integration. If you aren’t, your repository is hosted in Upsun and you can use the CLI or just Git itself.
At this stage, ensure you’ve already committed your updated files (mainly .upsun/config.yaml) in your Git history:
git add .upsun/config.yaml
git commit -m "Add Upsun configuration file"
  1. (Optional) Get your project ID by running the following command:
    upsun projects
    
  2. (Optional) Add Upsun as a remote repository by running the following command:
    upsun project:set-remote <VariableBlock name="PROJECT_ID" />
    
  3. Push to the Upsun repository by running the following command:
    upsun push
    
When you try to push, any detected errors in your configuration are reported and block the push. After any errors are fixed, a push creates a new environment.
If your application is deployed without error but you get a 502 error when loading your application, refer to the Troubleshoot page.

12. Test your production environment

When your Upsun project is successfully deployed:
  • Verify service connections:
    • Check database connectivity
    • Verify cache operations
    • Test background worker execution
  • Load testing: Run a load test against your Upsun environment before switching DNS to validate performance under realistic traffic. Tools like k6, Locust, or Gatling can be used for this purpose.
  • Review logs and metrics:
upsun logs app
upsun metrics:all
  • Verify functionality:
    • Test critical user flows
    • Confirm integrations working
    • Check scheduled jobs executing

13. Enable maintenance mode

Before importing data and switching DNS, enable maintenance mode in your application if it supports it. This prevents users from writing new data to your old environment during the cutover, avoiding data loss or inconsistencies.
Do not skip this step if your application is live and receiving traffic. Any writes to your old environment after the database export will be lost.

14. Import data

Once you have an environment ready and maintenance mode is enabled, import the data from your current provider. The exact process depends on the database engine you use.
Depending on the database engine you’re using, download a dump of your database into a SQL file locally and import it into your application container.
Then import the dump using the Upsun CLI:
upsun sql < <VariableBlock name="BACKUP_FILE_NAME" />
If you have multiple database services, target a specific one with --relationship=<RELATIONSHIP_NAME>.
For any potential more details, see the specific service documentation.

15. Import files

Your app may include content files, meaning files that aren’t intended to be part of your codebase and therefore aren’t tracked in Git. You can upload such files to mounts you created. Assuming you have the following mounts:
.upsun/config.yaml
applications:
  myapp:
    mounts:
      'web/uploads':
        source: storage
        source_path: uploads
      'private':
        source: instance
        source_path: private
Upload each mount separately:
upsun mount:upload --mount web/uploads --source ./uploads
upsun mount:upload --mount private --source ./private
Alternatively, you can transfer files using an SSH client.

16. Configure your domain and update DNS records

Lower your TTL in advance

Before switching DNS, lower your domain’s TTL to 300 seconds (5 minutes) at least 24 hours in advance. This reduces propagation delay during cutover and makes it easier to roll back quickly if needed.
Add your domain to Upsun:
upsun domain:add www.yourDomain.com
Get your Upsun target URL:
upsun environment:url

Update your DNS records

Add a CNAME record in your DNS provider pointing your domain to the URL returned above. Once DNS has propagated, verify your domain resolves correctly and your application loads as expected before disabling maintenance mode.
DNS propagation can take up to 48 hours depending on your provider and previous TTL value. You can monitor propagation using a tool like dnschecker.org.

Rollback plan

If something goes wrong after the DNS switch, you can revert quickly:
  • Point your CNAME back to your old provider’s URL
  • Re-disable maintenance mode on your old environment
  • Investigate the issue on Upsun before retrying
Keep your old environment live and intact until you have fully validated the migration.

17. Invite teams and users

You can either invite individual users to your project, or create teams and then invite users to teams (recommended).

Create a team and invite users

We recommend creating a team and inviting individual users to it, as you can manage access at the team level instead of one-by-one. When creating a team for a project, a role is required:
  • At the Project level: admin or viewer
  • For each environment type (production, staging and development): admin, contributor or viewer
To create a team, you can either use the Console or the CLI:
upsun team:create --role viewer,production:viewer,staging:contributor,development:admin --label "My team"
To invite a user to a team, provide the user ID (if existing user) or the email address:
upsun team:user:add <VariableBlock name="USER_EMAIL_ADDRESS_OR_ID" />
Each user invited to a team inherits the team’s role.

Invite individual users

When inviting individual users on a project, a role is required: To invite individual users on a project, use the following CLI command:
upsun user:add --role viewer,production:viewer,staging:contributor,development:admin <VariableBlock name="USER_EMAIL_ADDRESS" />

18. Monitor your application

Once your application is live, make sure to check out the continuous profiling feature to ensure your application is running as expected.

Troubleshooting common migration issues

If you encounter any error during the migration, refer to the Troubleshoot page.
Last modified on March 11, 2026