Migrate from Heroku to DigitalOcean App Platform
Validated on 9 Feb 2026 • Last edited on 9 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.
You’ll learn:
- 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 for lowest 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 via 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 to grab the private network connection string.
Read the Postgres and Valkey best practices documentation for more information about using VPCs with managed databases.
Step 3: Recreate Your App on App Platform
Now we’ll 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 → Apps.
-
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 and Region (match your database region).
-
Add Environment Variables: copy over your Heroku config vars. Set
DATABASE_URLto your DigitalOcean database connection string. -
Click Next and review your configuration, then Create Resources.
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 Create → 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 save.
Add a Pre-Deploy Job (Release Phase)
To replicate Heroku’s release phase, add a Job component:
-
From your app’s dashboard, click Create → Create Resources from Source Code.
-
Select the same repository and branch.
-
Change the Resource Type to Job.
-
Set the Kind to Pre-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, it’s time to 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 automated migration tools accessible from your DigitalOcean Databases panel or from our API. Our tool brings your data to DigitalOcean and keeps it in sync (for up to two weeks) with your source datastore, letting you choose when you are prepared to cutover.
- How to Migrate PostgreSQL Databases to DigitalOcean using Continuous Migration
- How to Migrate Valkey Databases to DigitalOcean
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 it to your App Platform app in the Control Panel under the Domains 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 propagation typically takes a few minutes to a few hours.
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.
Next 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.