Migrate from Heroku to DigitalOcean App Platform
Validated on 10 Feb 2026 • Last edited on 11 Feb 2026
App Platform is a fully managed Platform-as-a-Service (PaaS) that deploys applications from Git repositories or container images. It automatically builds, deploys, and scales components while handling all underlying infrastructure.
This guide walks you through migrating your Heroku-hosted applications and datastores to DigitalOcean App Platform.
It covers the following:
- How Heroku concepts map to DigitalOcean App Platform
- How to model a Heroku app as one or more App Platform components
- How to migrate your databases to DigitalOcean Managed Databases
- How to cut over DNS and finalize your migration
Why Migrate?
DigitalOcean App Platform offers a compelling alternative to Heroku, particularly as your application scales and your infrastructure needs evolve.
Key advantages:
-
Cost savings: Granular instance sizes from 512 MB to 32 GB of RAM at significantly lower price points.
-
Flexible scaling: Autoscaling with granular plan sizes, so scaling past 2.5 GB does not require moving directly to 14 GB.
-
Growth path beyond PaaS: Grow your application into DigitalOcean’s broader ecosystem with Managed Kubernetes, Spaces Object Storage, Gradient, Droplets, and more.
-
Free support for all users: Transparent, accessible support with clear upgrade paths and no enterprise sales process required.
-
Modern developer experience: Implement your infrastructure-as-code via App Spec (YAML), integrate with GitHub/GitLab/Bitbucket, auto-deploy on push, rollback when needed, and aggregate your monitoring with built-in log forwarding and health checks.
-
Dedicated IP addresses: Take advantage of free static IP addresses for each of your applications to make accessing your application straightforward and reliable.
Concept Mapping
Most Heroku concepts map cleanly to equivalent functionality on DigitalOcean App Platform. Use this table as a quick reference throughout your migration:
| Heroku | DigitalOcean App Platform |
|---|---|
| App | App |
| web process (Procfile) | Service (Web Service component) |
| worker / non-web process | Worker component |
| release phase | Job (PRE_DEPLOY kind) |
| Heroku Scheduler / clock process | Job (SCHEDULED kind, cron expression) |
| Config Vars | Environment Variables / App-Level Env Vars |
| Dyno | Container instance |
| Dyno type (Eco, Basic, Standard, etc.) | Instance size (Basic, Professional, etc.) |
| Heroku Postgres | DigitalOcean Managed PostgreSQL |
| Heroku Key-Value Store (Redis) | DigitalOcean Managed Redis / Valkey |
| Heroku Add-ons | DigitalOcean Marketplace / external services |
| Pipelines (review, staging, prod) | App-level environments / Deploy to DO Button |
| Procfile | App Spec (YAML) + Build/Run commands |
| Buildpacks | Cloud-Native Buildpacks (auto-detected) |
| heroku.yml / Docker deploys | Dockerfile-based builds |
| Custom domains + ACM | Custom domains + auto-managed TLS certs |
| Heroku CLI (heroku) | DigitalOcean CLI (doctl) |
Step 1: Prepare to Migrate
Before making any changes, take inventory of your Heroku resources and set up your DigitalOcean account.
Create Your DigitalOcean Account
Sign up at cloud.digitalocean.com if you haven’t already, then install and configure the DigitalOcean CLI (doctl) to manage resources from your terminal.
Authenticate with doctl to log in to your account:
doctl auth initThen validate that doctl is working:
doctl account getRead How to Install and Configure doctl for more help with setting up doctl.
Catalog Your Heroku Resources
Identify each Heroku app you want to migrate. For each app, note the following:
-
Procfile processes: web, worker, release, clock, and any other processes defined
-
Config Vars: All environment variables (especially DATABASE_URL, REDIS_URL, and API keys)
-
Add-ons: Heroku Postgres, Heroku Key-Value Store (Redis), and any third-party add-ons
-
Custom domains: Any custom domains and their DNS configuration
-
Buildpacks: Which language buildpacks your app uses
Step 2: Create Your Datastores
Create your DigitalOcean Managed Database clusters before deploying your app. This way, your services can connect on their first deployment.
Provision a Managed PostgreSQL Database
-
In the DigitalOcean Control Panel, click on the Create menu, then click Databases.
-
Select PostgreSQL as the database engine.
-
Choose a region (select the same region you plan to deploy your app in to minimize latency).
-
Select an instance size and storage amount. Start small for testing, as you can scale up before the final migration.
-
Click Create Database Cluster. Provisioning takes a few minutes.
-
Once ready, navigate to the database’s Connection Details tab. Copy the connection string to add it to your app’s environment variables in the following step.
Provision a Managed Valkey (Redis) Instance
If your Heroku app uses Heroku Key-Value Store (Redis), follow the same process but select Valkey as the database engine. Copy the connection string for use as your REDIS_URL environment variable.
DigitalOcean Managed Databases support private networking through VPC. When your App Platform app is in the same region as your database, traffic stays on the private network which is faster and more secure. To take full advantage of this feature, select the VPC network option in your database’s Connection Details panel and copy the private network connection string.
Read the Postgres and Valkey best practices documentation to use VPCs with managed databases.
Step 3: Recreate Your App on App Platform
Create the App Platform resources that correspond to your Heroku app’s processes.
Understanding Your Procfile
Most Heroku apps define a Procfile in the repo root. The following code listing shows an example Node.js Procfile and how each process maps to App Platform:
# Procfile
web: npm run start
worker: npm run worker
release: db-migrate -e prod up
| Procfile Entry | App Platform Component | Notes |
|---|---|---|
| web | Service (Web Service) | Receives HTTP traffic, gets a public URL |
| worker | Worker | Background processing, not internet-accessible |
| release | Job (PRE_DEPLOY) | Runs before each deploy (for example, DB migrations) |
Create a Web Service
-
In the DigitalOcean Control Panel, click Create, then App Platform.
-
Connect your GitHub, GitLab, or Bitbucket repository and select the branch to deploy.
-
App Platform auto-detects your language. Confirm the Resource type is set to Web Service.
-
Configure your Build command (
npm install, for example) and Run command (npm run start). -
Select your Instance size.
-
Add Environment variables: copy over your Heroku config vars. Set
DATABASE_URLto your DigitalOcean database connection string. -
Select your Datacenter region (match your database region).
-
Review your configuration, then click Create app.
Add Worker Components
For each non-web process in your Procfile, add a Worker component to the same app:
-
From your app’s dashboard, click Add components, then Create resources from source code.
-
Select the same repository and branch.
-
Change the Resource type to Worker.
-
Set the Run command to your worker’s start command (for example
npm run worker). -
Configure environment variables as needed, then click Add resources.
Add a Pre-Deploy Job (Release Phase)
To replicate Heroku’s release phase, add a Job component:
-
From your app’s dashboard, click Add components, then Create resources from source code.
-
Select the same repository and branch.
-
Change the Resource type to Job.
-
Set the Job Trigger to Before every deploy. This ensures the job runs before each deploy and blocks deployment if it fails, the same as Heroku’s release phase.
-
Set the Run command to your migration command (for example
db-migrate -e prod up).
0 */6 * * * for every 6 hours). This runs directly on App Platform with no external scheduler needed.
For infrastructure-as-code workflows, you can define your entire app in a single YAML file and deploy it using doctl. This is the App Platform equivalent of combining your Procfile + app.json into one declarative specification.
Example App Spec translating the example Procfile
name: my-app
region: nyc
services:
- name: web
github:
repo: your-org/your-repo
branch: main
build_command: npm install
run_command: npm run start
http_port: 8080
instance_size_slug: basic-xxs
instance_count: 1
envs:
- key: DATABASE_URL
scope: RUN_TIME
value: "${db.DATABASE_URL}"
workers:
- name: background-worker
github:
repo: your-org/your-repo
branch: main
build_command: npm install
run_command: npm run worker
instance_size_slug: basic-xxs
jobs:
- name: db-migrate
github:
repo: your-org/your-repo
branch: main
build_command: npm install
run_command: db-migrate -e prod up
kind: PRE_DEPLOY
instance_size_slug: basic-xxs
databases:
- name: db
engine: PG
production: true
cluster_name: my-db-clusterDeploy with a single doctl command:
doctl apps create --spec app-spec.yamlTo update existing apps from App Spec YAML, use the following doctl command:
doctl apps update <your-app-id> --spec app-spec.yamlSet Environment Variables
App Platform environment variables work similarly to Heroku config vars. A few things to note:
-
Component-level vs. App-level: Environment variables can be scoped to individual components or shared across all components in an app.
-
Bindable variables: When you attach a DigitalOcean Managed Database to your app, App Platform provides bindable variables (like
${db.DATABASE_URL}) that automatically contain your connection details. -
Build vs. Runtime scope: You can specify whether a variable is available at build time, runtime, or both.
-
Encryption: Select Encrypt for sensitive values to store them securely. Encrypted variables cannot be read back from the dashboard.
Step 4: Migrate Data and Cut Over
With your App Platform app running and connected to its new (empty) databases, move your production data and switch traffic over.
Scale Up Your DigitalOcean Databases
Before importing data, ensure your DigitalOcean databases have enough storage and compute for your production workload. You can resize database clusters in the Control Panel at any time. To prepare for production workloads, we strongly recommend taking this time to add at least one standby node to gain automatic failover. Refer to the How to Add Standby Nodes guides (for Postgres and for Valkey).
Enable Maintenance Mode on Heroku
Put your Heroku app into maintenance mode so no new writes occur during migration:
heroku maintenance:on --app <YOUR_HEROKU_APP_NAME>Migrate Your Database into DigitalOcean Managed Database
DigitalOcean provides the following automated migration tools accessible from your DigitalOcean Databases panel or from our API. These tools transfer your data to DigitalOcean and keep it in sync with your source datastore for up to two weeks, letting you choose when to cut over.
Verify Your Application
Before switching DNS, verify that everything works correctly on your App Platform deployment:
-
Visit your app’s auto-assigned
.ondigitalocean.appURL. -
Test critical user flows and API endpoints.
-
Verify database connectivity and data integrity.
-
Check that background workers are processing jobs correctly.
-
Review application logs in the App Platform dashboard.
Update Your DNS Records
If your Heroku app uses a custom domain, add your custom domain to your App Platform app in the Control Panel under the Networking tab. Then update your DNS records to point to DigitalOcean instead of Heroku:
-
For apex domains: Add an A record pointing to the IP provided by App Platform.
-
For subdomains: Add a CNAME record pointing to your app’s
.ondigitalocean.apphostname.
App Platform automatically provisions and manages TLS certificates for your custom domains. DNS changes can take up to 72 hours to propagate. You can track progress in the App Platform dashboard.
Migrate CDN Traffic
If your Heroku application uses a CDN (commonly via add-ons such as Expedited CDN or similar reverse-proxy CDNs), this functionality does not migrate automatically. You must explicitly reconfigure CDN delivery when cutting over to DigitalOcean.
Remove Heroku CDN Dependencies
Before cutover:
- Disable or remove any Heroku CDN add-ons.
- Remove any CDN-specific configuration that assumes Heroku headers, hostnames, or proxy behavior.
- Confirm your application serves correct cache headers (
Cache-Control,ETag,Last-Modified) for static assets.
Verify CDN Behavior on App Platform
After deploying your app to App Platform:
- Access the default
*.ondigitalocean.appURL. - Confirm that static assets are being served correctly.
- Inspect response headers to ensure assets are cacheable.
App Platform respects standard HTTP caching headers. If assets are not cached, review your application or framework configuration.
AI-Assisted Migration: Heroku to App Platform
The following prompt serves as a migration orchestrator. It guides an AI assistant to execute CLI commands in a structured sequence to help you inventory, map, and deploy your Heroku application to DigitalOcean. This is an assisted workflow designed for functional testing and staging environments.
The process is designed for situations where you don’t have the source code locally. The agent is prompted to pull everything directly from Heroku, inventory your entire setup (dynos, environment variables, add-ons, domains, databases), and reconstruct it as a DigitalOcean app spec YAML file. The migration includes built-in checkpoints where you review and approve decisions before anything gets deployed or modified.
Prerequisites
The following CLI tools must be installed and authorized to their respective accounts:
heroku: Heroku CLI, logged in to your Heroku account (check withheroku auth:whoami)doctl: DigitalOcean CLI, authenticated with the target DigitalOcean team account (check withdoctl account get)gh: GitHub CLI, authenticated with the GitHub account containing your app repo (check withgh auth status)git: for cloning and pushing repositoriespsql(andpg_dump/pg_restore): PostgreSQL client tools for database migration
Supported App Types
The prompt can migrate the following types of apps:
- Web apps with a
Procfile(such as Node.js, Python, Ruby, Go, or PHP) - Apps using Heroku buildpacks or Docker
- Apps with any combination of web dynos, workers, clock processes, and release phase commands
- Apps using Heroku Postgres, Redis, or third-party add-ons accessible via environment variables
Repository Requirements
The following code repositories are supported:
- Apps connected to a GitHub repo (this is preferred, as App Platform can deploy directly from GitHub)
- Apps with code only on Heroku’s git remote (the prompt handles pushing to GitHub)
- Private or public repositories
The following features are not supported by the migration prompt:
- Heroku Pipelines or Review Apps: these need manual recreation.
- Heroku Scheduler: must be mapped to DigitalOcean’s Scheduled Jobs or an external cron service.
- Heroku Private Spaces or Shield: contact DigitalOcean for VPC equivalents.
- Multi-region or high-availability database replication: plan and configure separately.
- DNS cutover: the prompt explicitly leaves DNS changes to you.
Help me migrate my Heroku app to DigitalOcean App Platform using doctl.
I don't have the source code locally, so we need to start from Heroku.
Reference: https://docs.digitalocean.com/products/app-platform/getting-started/migrate-from-heroku/
## Step 1: Discover my Heroku app
Run these commands to inventory my Heroku app:
- `heroku apps` — list my apps so I can tell you which one to migrate
- Then for the app I choose, gather ALL of the following:
- `heroku ps --app <APP>` — dyno types and counts
- `heroku config --app <APP>` — all config/env vars
- `heroku addons --app <APP>` — all add-ons (DB, Redis, etc.)
- `heroku domains --app <APP>` — custom domains
- `heroku apps:info --app <APP>` — general app info (stack, git URL, region)
- `heroku labs --app <APP>` — any enabled labs features
- `cat Procfile` (after cloning) — process types
## Step 2: Get the source code
- Determine if the app is connected to a GitHub repo (from apps:info)
- If yes: clone from GitHub using `gh repo clone <repo>`
- If no: use `heroku git:clone --app <APP>` to pull the source from Heroku
- Push the code to my GitHub account if it's not already there
(use `gh repo create` + `git push`)
## Step 3: Provision the DO managed database FIRST
Before building the app spec, create the managed database separately:
- Use `doctl databases create` to create a managed Postgres (or Redis/MySQL)
cluster in the same region as the app
- Do NOT use the `db-s-dev-database` size. Even for testing, these embedded
databases lack the disk/RAM required for standard `pg_restore` operations.
Use a proper managed database size like `db-s-1vcpu-1gb` or larger.
- Wait for the database to be ready, then get its connection details
using `doctl databases connection <DB_ID>`
- Note the cluster name, database name, host, port, and credentials —
you'll need these for the app spec
## Step 4: Build the DO app spec
Based on everything discovered above:
- Map Procfile processes to DO components (web → Service, worker → Worker,
release → Pre-Deploy Job, clock/scheduled → Scheduled Job)
- Map Heroku dyno sizes to appropriate DO instance sizes
- Map all config vars to environment variables (mark sensitive ones
like API keys, secrets, and passwords as encrypted)
- Map Heroku add-ons to DO equivalents or note which third-party
add-ons can stay as-is by keeping their env vars
- Reference the managed database created in Step 3 using `cluster_name`
and `db_name` in the database component of the app spec, rather than
letting App Platform create an embedded dev database
- Create the app-spec.yaml file
## Step 5: Deploy with doctl
- `doctl apps create --spec app-spec.yaml`
- Poll deployment status every 10 seconds until it succeeds or fails
- Show me the live `.ondigitalocean.app` URL when done
## Step 6: Migrate database data
After the app is deployed and running:
- Confirm which database the app is actually connected to — do NOT assume
it's `defaultdb`. The managed DB cluster may contain multiple databases.
Use `doctl databases connection <DB_ID>` and `\l` in psql to verify
the exact database name before restoring.
- `pg_dump` the Heroku database using `--no-owner --no-acl --format=custom`
(this is read-only and does not modify Heroku)
- `pg_restore` into the correct DO database using `--no-owner --no-acl`
- Verify row counts in key tables after restore
- Strip Heroku-specific artifacts: `_heroku.*` event triggers and
`transaction_timeout` errors during restore are expected and harmless
## Step 7: Functional Verification
Provide a checklist of the components deployed (Services, Workers, DBs). Remind
me that this is a test environment and that I should verify application logic
and connectivity before considering a production DNS cutover.
## Important rules:
- Pause after Step 1 and show me what you found before proceeding —
let me confirm which app and review the config
- Pause again after Step 4 to let me review the app spec before deploying
- Do NOT change DNS records — I'll do that after verifying everything works
- Flag any Heroku add-ons that don't have a direct DO equivalent
so we can discuss alternatives
## DigitalOcean preferences:
- Region: <PICK ONE: nyc / sfo / ams / lon / sgp / blr, or say "same as Heroku">
- Instance sizing: recommend based on my Heroku dyno typesNext Steps
After you’ve successfully migrated from Heroku to DigitalOcean App Platform, explore some other capabilities of the DigitalOcean platform:
-
Autoscaling: Configure horizontal autoscaling based on CPU or HTTP request metrics to handle traffic spikes automatically.
-
Log forwarding: Stream application logs to Papertrail, Datadog, Logtail, or your own OpenSearch cluster.
-
Alerts and monitoring: Set up alert policies for deployment failures, resource usage thresholds, and health check failures.
-
Rollbacks: Instantly roll back to a previous deployment if issues arise.
-
App Spec in CI/CD: Commit your app spec YAML to your repo and use doctl in your CI pipeline for GitOps-style deployments.
-
Managed Kubernetes: When you need more control, DigitalOcean Kubernetes (DOKS) provides a natural next step, no vendor change required.
-
DigitalOcean MCP Server: Integrate AI-powered coding assistants like Claude Code directly with App Platform for streamlined development workflows.
Get Support
If you need help with your migration, DigitalOcean offers several support channels:
-
Support tickets: Available to all users from the Control Panel. Contact support to get started.
-
Community Q&A: Ask questions and find answers at DigitalOcean Community Q&A.
-
App Platform Documentation: More guides are available in the App Platform section.