Skip to main content
A Heroku app moves to Sevalla as an application with one process per Procfile entry, Sevalla databases in place of its add-ons, and environment variables in place of its config vars. You recreate the setup while the Heroku app keeps running, copy the data during a short maintenance window, then point the domains at Sevalla.

At a glance

Environment variables

How Heroku maps to Sevalla

Before you begin

  • The Heroku CLI, signed in to the account that owns the app.
  • The app’s code in a repository on GitHub, GitLab or Bitbucket. Sevalla doesn’t deploy from Heroku’s Git remote. See Git providers.
  • A Sevalla company with a payment method.
  • The PostgreSQL client tools, at the same major version as Heroku Postgres or newer, if the app uses Heroku Postgres. See Import and export PostgreSQL.
  • A maintenance window: the Heroku app is in maintenance mode while you copy the data.

Take stock of the Heroku app

Collect what you’ll recreate, with your app’s name in place of storefront:
  • apps:info shows the region and the stack. Heroku’s us region runs in northern Virginia and eu in Ireland; the closest Sevalla locations are Ashburn, USA and London, UK. See Locations.
  • addons lists what becomes a database, a bucket or a third-party service. Services that connect through config vars, such as email or error tracking, keep working when you copy their variables.
  • pg:info shows the PostgreSQL version (PG Version). Create the Sevalla database with the same version or a newer one.
  • heroku.env holds every config var as KEY=value. It contains secrets: don’t commit it.
  • Keep your Procfile at hand: each line becomes a process.

Create the databases

1

Create the PostgreSQL database

In the sidebar, click Databases, then click Create database. Under Database, choose PostgreSQL and a version at least as new as Heroku’s. Enter orders-db as the Display name, choose the Data center the application will use and a Size with room for the data, then click Create database.
2

Create the Redis database

If the app uses Heroku Key-Value Store, create a second database the same way: choose Redis, enter storefront-redis as the Display name, and choose the same Data center. See Create a database.

Create the application

1

Create it from the repository

In the sidebar, click Applications, then click Create > Application. Under Source, click Private repository, then choose the Git provider, the Repository and the Branch. Under Location, choose the same Data center as the databases, choose a Size, and click Create application. The application opens on its Overview tab with the status Not deployed yet: creating an application doesn’t deploy it. See Create an application.
2

Keep Heroku's buildpacks, if you want

Sevalla builds with Ingot by default, which detects most languages without configuration and starts the web process with the Procfile’s web entry. To build the way Heroku does, click the Settings tab, then click Update build strategy under Build strategy. Choose Buildpacks, set the Pack builder to heroku/builder:24, and click Update build strategy. See Buildpacks.
A web process on H1 can’t have custom domains. If you’ll move a domain, choose a larger size, such as S1.

Connect the databases

1

Connect PostgreSQL

Click the Networking tab. Under Connected services, click Add internal connection. Choose orders-db as the Service and turn on Add environment variables to the application. Change the key DB_URL to DATABASE_URL, the name your code already reads, and click Add internal connection.
2

Connect Redis

Add an internal connection to storefront-redis the same way. Its URL is already called REDIS_URL.
The PostgreSQL URL starts with postgres://, like Heroku’s. The Redis URL starts with redis://, where Heroku Key-Value Store’s starts with rediss:// (TLS): if your code passes TLS options for it, such as ssl_cert_reqs=None with redis-py, remove them. See Connect an application.

Add the config vars

1

Clean up the exported file

In heroku.env, delete DATABASE_URL, REDIS_URL and the other variables that Heroku add-ons set, such as HEROKU_POSTGRESQL_* or REDIS_TLS_URL: the internal connections replace them. Update any value that contains the Heroku domain, such as allowed hosts, to the application’s sevalla.app domain under its name in the page header.
2

Import the file

Click the Environment variables tab, then click Add environment variables. Click Import .env and choose heroku.env, or paste its contents into a key field. Keep Available during runtime and Available during buildtime selected, and click Add environment variables.
The Add environment variables sheet with key and value rows, Add another, Import .env and the availability optionsThe Add environment variables sheet with key and value rows, Add another, Import .env and the availability options
Don’t add PORT: Sevalla sets it to the web process’s port. See Environment variables.

Recreate the Procfile processes

On the Processes tab, click Create process for each entry. Choose Background worker, Cron job or Job, enter a Name and the Custom start command, set the Start policy (jobs) or the Schedule (cron jobs), choose a Resource, and click Create process. Ingot and Buildpacks don’t run the release entry, so the job is what runs it, once per deployment, before the new version starts. You can delete the release line from the Procfile. Commands that use $PORT keep working: Sevalla sets PORT like Heroku does. See Processes.

Copy the PostgreSQL data

1

Stop writes on Heroku

Turn on maintenance mode, which answers visitors with Heroku’s maintenance page, and stop the workers:
2

Download a backup

The backup downloads as latest.dump, a custom-format archive.
3

Open the Sevalla database to your computer

In the sidebar, click Databases, then click orders-db. Click the Networking tab, click Enable under External connection, then click Enable in the dialog. Copy the External hostname, External port and password. See Enable the external connection.
4

Restore the backup

Restore latest.dump with pg_restore, as in Import a database.
To rehearse, run these steps once without maintenance mode, deploy, and test on the sevalla.app domain. For the real cutover, empty the database first, for example with pg_restore’s --clean --if-exists options, so the restore doesn’t collide with the rehearsal’s tables.

Copy the Redis data

Skip this when Redis holds only caches or jobs you can lose: the application refills it. Heroku Key-Value Store doesn’t document an export, so copy the keys with DUMP and RESTORE:
1

Open the Redis database to your computer

Enable the external connection of the Sevalla Redis database, as for PostgreSQL, and copy its External connection URL.
2

Copy the keys

Save this script, then run it with both URLs:
copy_redis.py
The script copies database 0, the one in both URLs, and keeps each key’s expiry. If RESTORE fails with DUMP payload version or checksum are wrong, the Sevalla database runs an older version than Heroku’s: create it with a newer version. See Import and export Redis.

Deploy and verify

1

Deploy

On the application’s Overview tab, click Deploy now under Recent deployments, check the Branch, and click Deploy.
2

Check the deployment

On the Deployments tab, wait for the status Deployed. The build log shows each job’s result, such as Migrate has been successful.With the API, Get deployment (getDeploymentV3) returns the status, success for Deployed, and Get application deployment logs (getApplicationDeploymentLogsV3) finds the job’s result. APP_ID and DEPLOYMENT_ID come from Deploy with the API, where the job is named release, after its Procfile entry:
3

Test the application

Click the domain under the application’s name and test the critical paths: sign-in, a write to the database, a background task. On the Processes tab, the web process and the background workers show Running.With the API, Get application runtime logs (getApplicationRuntimeLogsV3) with search finds a line that a worker logs, for example celery@... ready. for Celery:
CLI: sevalla apps logs runtime "$APP_ID" --search ready. MCP: search_runtime_logs.
4

Turn on auto-deploy

To deploy every push to the branch automatically, click the Settings tab, then click Update auto-deploy in the Auto-deploy section. Turn on Auto-deploy and click Update auto-deploy. See Deployments.

Move the custom domains

1

Add each domain

On the application’s Domains tab, click Add custom domain, enter the domain in Domain name, for example shop.example.com, and click Add custom domain.
2

Verify it

Add the ownership and certificate records that Sevalla shows at your DNS provider. Heroku keeps serving the domain meanwhile. When the domain’s status changes to Pointing, its certificate is ready. See Verify the domain.
3

Point it at Sevalla

Replace the record that points at Heroku (a CNAME to a herokudns.com target) with the pointing record that Sevalla shows. The status changes to Active when Sevalla sees it. See Point the domain.
Add the custom domains to any setting that lists allowed hosts, such as Django’s ALLOWED_HOSTS, then deploy.

Shut down the Heroku app

When the domains are Active and traffic reaches Sevalla:
  1. Disable the external connections you opened: on each database’s Networking tab, click Disable under External connection, then click Disable in the dialog.
  2. Keep latest.dump until you no longer need it.
  3. Stop the Heroku app with heroku ps:scale web=0 --app storefront, and delete it with heroku apps:destroy --app storefront once you’re sure. Deleting a Heroku app deletes its add-ons and their data.
To repeat the setup for staging and review apps, put the applications in a pipeline and turn on preview apps.

Deploy with the API

This sequence does what Create the databases to Deploy and verify do in the dashboard, with the Sevalla API and Ingot: it creates the databases and the application, adds the config vars, turns each Procfile entry into its process, and deploys. A script or an AI agent runs it as is, in one shell, from the root of the repository, where the Procfile is. Each step names the CLI command and the Sevalla MCP server tool that do the same. You need:
  • An API key with the Company developer role, in SEVALLA_API_KEY.
  • The repository on GitHub, and a GitHub account with access to it connected to Sevalla. The API has no call that reports the connection: without access, the step that creates the application fails with 400 and Cannot access repository https://github.com/acme/storefront: Repository not found or you don't have access., followed by where to connect a Git account (My account in the dashboard) and, for GitHub, to give Sevalla’s GitHub App access to the repository.
  • The Heroku CLI, signed in, plus curl, jq and openssl.
Export the config vars as JSON, and drop the ones that Heroku add-ons set, which the internal connections replace. Then update any value that contains the Heroku domain, such as allowed hosts, in config.json:
Both files contain secrets: don’t commit them.
1

Choose the location

List clusters (listClustersV3) returns every location with its region ID in location. Save the one closest to the Heroku region, here eu-frankfurt-1 (Frankfurt, Germany) for Heroku’s us region:
CLI: sevalla resources clusters. MCP: get_platform_options.
2

Look up the process size

List process resource types (listProcessResourceTypesV3). Save S1 for the processes this sequence creates:
CLI: sevalla resources process-types. MCP: get_platform_options.
3

Look up the database size

List database resource types (listDatabaseResourceTypesV3). Pick a size with room for the data; here DB1, the smallest:
CLI: sevalla resources db-types. MCP: get_platform_options.
4

Look up the database versions

List database versions (listDatabaseVersionsV3) returns the versions the location offers, oldest first. Save the newest PostgreSQL and Redis versions, which are at least as new as Heroku’s:
CLI: sevalla resources db-versions --cluster "$CLUSTER_ID". MCP: not needed, create_database takes the newest version by default.
5

Create the PostgreSQL database

Create database (createDatabaseV3). You choose the password, and the API never returns it, so keep it for the connection URL:
CLI: sevalla databases create --name orders-db --type postgresql --db-version "$PG_VERSION" --cluster "$CLUSTER_ID" --resource-type "$DB_SIZE_ID" --db-name storefront --db-user storefront --db-password "$PG_PASSWORD". MCP: create_database; with connect_to_application_id and env_var_name: "DATABASE_URL", once the application exists, it also does the internal connection and adds DATABASE_URL as a postgresql:// URL.
6

Create the Redis database

Create database (createDatabaseV3) again. Skip this step and the other Redis steps if the app doesn’t use Heroku Key-Value Store:
CLI: sevalla databases create --name storefront-redis --type redis --db-version "$REDIS_VERSION" --cluster "$CLUSTER_ID" --resource-type "$DB_SIZE_ID" --db-name storefront --db-password "$REDIS_PASSWORD". MCP: create_database with type: "redis" and env_var_name: "REDIS_URL".
7

Wait for the databases

Get database (getDatabaseV3) shows status ready when a database is up, with its internal hostname and port:
CLI: sevalla databases get "$PG_ID". MCP: get_database.
8

Create the application

Create application (createApplicationV3) creates the application with a web process at S1, which can have custom domains, and doesn’t deploy it:
CLI: sevalla apps create --name storefront --cluster "$CLUSTER_ID" --source privateGit --git-type github --repository "$REPO" --branch main. MCP: create_application with deploy: false.
9

Connect the databases

Create internal connection (createApplicationInternalConnectionV3), once per database:
The API adds no environment variables; the next step adds the two URLs. CLI: sevalla apps internal-connections create "$APP_ID" --target-id "$PG_ID" --target-type database. MCP: sevalla_api_create with createApplicationInternalConnectionV3 and the same body.
10

Add the environment variables

Create environment variable (createEnvironmentVariableV3), once per variable: DATABASE_URL and REDIS_URL in the format the internal connections use, then every entry of config.json:
It prints each key as it’s added. CLI: sevalla apps env-vars create "$APP_ID" --key <key> --value <value>, once per variable. MCP: set_environment_variables with all the variables in one call.
11

Create the Procfile processes

Create process (createProcessV3), once per Procfile entry other than web: a job with the start policy beforeDeployment for release, and a background worker for every other entry, its command after exec. Each process is named after its entry:
For the Procfile in Recreate the Procfile processes, it prints {"display_name":"worker","type":"worker","entrypoint":"exec celery -A storefront worker"} and {"display_name":"release","type":"job","entrypoint":"python manage.py migrate"}. CLI: sevalla apps processes create "$APP_ID" --name worker --type worker --resource-type "$S1_ID" --command "exec celery -A storefront worker", and for the job --type job --job-start-policy beforeDeployment. MCP: sevalla_api_create with createProcessV3 and the same body.
12

Create the cron jobs

Create process (createProcessV3) with type cron, once per Heroku Scheduler job, with its command and a cron schedule in UTC:
CLI: sevalla apps processes create "$APP_ID" --name "Clear sessions" --type cron --resource-type "$S1_ID" --command "python manage.py clearsessions" --schedule "*/10 * * * *". MCP: sevalla_api_create with createProcessV3 and the same body.
13

Deploy

Trigger deployment (triggerDeploymentV3) deploys the latest commit of the branch:
CLI: sevalla apps deployments trigger "$APP_ID". MCP: trigger_deployment.
14

Wait for the deployment

Get deployment (getDeploymentV3) reports the status, which ends as success, failed, cancelled or skipped. The loop keeps polling through a failed request, for up to 30 minutes:
CLI: sevalla apps deployments get "$DEPLOYMENT_ID" --app-id "$APP_ID". MCP: get_deployment.
15

Turn on auto-deploy

Update application (updateApplicationV3):
It prints true. CLI: sevalla apps update "$APP_ID" --data '{"auto_deploy": true}'. MCP: sevalla_api_update with updateApplicationV3 and the same body.
Then run the checks in Deploy and verify. To build with Heroku’s buildpacks instead of Ingot, update the application with {"build_type": "pack", "pack_builder": "heroku/builder:24"} before you deploy (CLI: sevalla apps update "$APP_ID" --data '{"build_type": "pack", "pack_builder": "heroku/builder:24"}'). The data copy needs the database’s external connection: Toggle external connection (toggleDatabaseExternalConnectionV3) turns it on and off, and Get database then returns external_hostname and external_port. Add application domain (addApplicationDomainV3) adds each custom domain and returns the DNS records in dns_records.