Skip to content

Commit 8e97fb9

Browse files
Merge pull request #311733 from craigshoemaker/aca/heroku
[Container Apps] New: Add Heroku migration guidance
2 parents debf89e + 004e71d commit 8e97fb9

5 files changed

Lines changed: 640 additions & 1 deletion

File tree

articles/container-apps/TOC.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,12 @@ items:
177177
href: troubleshoot-target-port-settings.md
178178
- name: Container start
179179
href: troubleshoot-container-start-failures.md
180+
- name: Migration
181+
items:
182+
- name: Heroku migration overview
183+
href: migrate-heroku-overview.md
184+
- name: Migrate from Heroku
185+
href: migrate-heroku.md
180186
- name: AI integration
181187
items:
182188
- name: Overview

articles/container-apps/code-to-cloud-options.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,4 @@ In Azure Container Apps, you can use the [Azure CLI](/cli/azure/) or the [Azure
9797

9898
- [Deploy to Azure Container Apps using Visual Studio](deploy-visual-studio.md)
9999
- [Deploy to Azure Container Apps using Visual Studio Code](deploy-visual-studio-code.md)
100+
- Migrating from Heroku? See [Heroku to Azure Container Apps migration overview](migrate-heroku-overview.md).

articles/container-apps/migrate-functions.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,4 +197,5 @@ Improve reliability after migration:
197197
198198
## Related content
199199
200-
- [Functions on Azure Container Apps overview](/azure/container-apps/functions-usage)
200+
- [Functions on Azure Container Apps overview](/azure/container-apps/functions-usage)
201+
- [Heroku to Azure Container Apps migration overview](migrate-heroku-overview.md)
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
---
2+
title: Heroku to Azure Container Apps overview
3+
description: Plan your migration from Heroku to Azure Container Apps with concept mapping, service equivalents, cost comparison, and pitfalls to avoid.
4+
ms.service: azure-container-apps
5+
ms.topic: conceptual
6+
ms.date: 02/12/2026
7+
ms.author: simonjakesch
8+
author: simonjj
9+
ms.reviewer: cshoe
10+
ms.custom: migration-heroku
11+
ms.ai-usage: ai-assisted
12+
---
13+
14+
# Heroku to Azure Container Apps migration overview
15+
16+
If you're moving from Heroku to Azure Container Apps, this guide helps you plan the migration by mapping the Heroku concepts you already know to their Azure equivalents. Use this article to assess the scope of your migration, identify the Azure services you need, and avoid common pitfalls before you start.
17+
18+
For step-by-step migration procedures, see [Migrate an app from Heroku to Azure Container Apps](migrate-heroku.md).
19+
20+
## Concept mapping
21+
22+
The following table maps core Heroku platform features to their Azure Container Apps equivalents.
23+
24+
| Heroku concept | Azure Container Apps equivalent | Notes |
25+
| --- | --- | --- |
26+
| App (web dyno) | [Container App](/azure/container-apps/overview) | A single deployable unit running your application code. |
27+
| Dyno types + manual scaling | [KEDA-based autoscaling](/azure/container-apps/scale-app) | Rule-based autoscaling that includes scale-to-zero. Replaces manual dyno count management. |
28+
| Buildpacks (slug compilation) | Container images or [Cloud Native Buildpacks](/azure/container-apps/containerapp-up) | Use `az containerapp up --source` for a buildpack-like experience, or bring your own Dockerfile. |
29+
| Config Vars | [Environment variables](/azure/container-apps/environment-variables) + [Azure Key Vault](/azure/key-vault/general/overview) | Nonsensitive values use environment variables. Secrets use Key Vault references or Container Apps secrets. |
30+
| Add-ons (Postgres, Redis, etc.) | Azure managed services | See [Service equivalents](#service-equivalents) for a full mapping. |
31+
| `heroku` CLI | [`az containerapp` CLI](/cli/azure/containerapp) | Azure CLI with the `containerapp` extension provides equivalent management commands. |
32+
| Heroku Pipelines / Review Apps | [GitHub Actions](/azure/container-apps/github-actions) or [Azure Pipelines](/azure/container-apps/azure-pipelines) | CI/CD pipelines you configure and own. |
33+
| One-off dynos (`heroku run`) | [Container Apps jobs](/azure/container-apps/jobs) | On-demand or scheduled execution without a long-running app. |
34+
| Procfile (process types) | Separate Container Apps per process type | Deploy your web and worker processes as independent Container Apps within the same environment. |
35+
| Custom domain + ACM | [Custom domain + free managed certificate](/azure/container-apps/custom-domains-managed-certificates) | Managed certificates are free and autorenew. |
36+
37+
## Service equivalents
38+
39+
When you migrate from Heroku, replace Heroku add-ons with Azure managed services. The following table maps common add-ons to their Azure equivalents.
40+
41+
| Heroku add-on | Azure equivalent | Migration complexity |
42+
| --- | --- | --- |
43+
| Heroku Postgres | [Azure Database for PostgreSQL - Flexible Server](/azure/postgresql/flexible-server/overview) | Medium: requires data export and restore. |
44+
| Heroku Redis | [Azure Cache for Redis](/azure/azure-cache-for-redis/cache-overview) | Low: typically no data migration needed (cache-only use). |
45+
| Heroku Scheduler | [Container Apps jobs](/azure/container-apps/jobs) (scheduled type) | Low — recreate cron expressions as job schedules. |
46+
| Papertrail / Logentries | [Azure Monitor + Log Analytics](/azure/azure-monitor/overview) | Low — logging is built in to Container Apps. |
47+
| New Relic | [Azure Application Insights](/azure/azure-monitor/app/app-insights-overview) | Medium — requires SDK or auto-instrumentation changes. |
48+
| SendGrid | [SendGrid via Azure Marketplace](https://azuremarketplace.microsoft.com/marketplace/apps/sendgrid.tsg-saas-offer) or [Azure Communication Services](/azure/communication-services/overview) | Low — SendGrid continues to work from Azure; update connection details only. |
49+
| CloudAMQP (RabbitMQ) | [Azure Service Bus](/azure/service-bus-messaging/service-bus-messaging-overview) | High — different messaging API; requires code changes. |
50+
| Heroku Kafka | [Azure Event Hubs](/azure/event-hubs/event-hubs-about) (Kafka-compatible endpoint) | Low — Event Hubs supports the Kafka protocol directly. |
51+
| Bucketeer / S3 add-ons | [Azure Blob Storage](/azure/storage/blobs/storage-blobs-overview) | Medium — requires SDK or API changes for file operations. |
52+
| Memcachier | [Azure Cache for Redis](/azure/azure-cache-for-redis/cache-overview) | Low — Redis supports memcache-compatible protocols. |
53+
| Heroku Connect (Salesforce) | [Azure Logic Apps](/azure/logic-apps/logic-apps-overview) or Power Automate | High — different integration approach; requires workflow redesign. |
54+
55+
For each add-on in your Heroku app, follow this general pattern:
56+
57+
1. Provision the Azure equivalent service.
58+
1. Migrate any persistent data (databases, storage).
59+
1. Update connection strings and credentials in your Container App environment variables.
60+
1. Validate the integration before removing the Heroku add-on.
61+
62+
## Scaling comparison
63+
64+
Heroku uses a fixed-dyno model where you set a specific instance count. Azure Container Apps uses rule-based autoscaling powered by [KEDA](https://keda.sh), which adjusts replicas based on demand.
65+
66+
| Capability | Heroku | Azure Container Apps |
67+
| --- | --- | --- |
68+
| Scale mechanism | Manual dyno count | Rule-based autoscaling (HTTP, CPU, queue length, cron, custom) |
69+
| Scale to zero | Not available | Supported - no cost when idle |
70+
| Minimum instances | At least 1 dyno required | Configurable: 0 or more replicas |
71+
| Maximum instances | Plan-dependent | Up to 300 replicas per container app |
72+
| Scale triggers | None - manual only | HTTP concurrency, TCP connections, CPU, memory, Azure Queue, custom KEDA scalers |
73+
74+
### Key scaling concepts
75+
76+
- **`min-replicas: 0`** enables scale-to-zero when no traffic is present, which eliminates cost for idle apps.
77+
- **`max-replicas`** caps the number of instances to control costs. Start conservatively and adjust based on monitoring data.
78+
- **HTTP concurrency scaling** is the simplest starting point for web apps. It adds replicas when concurrent requests per instance exceed your threshold.
79+
- **Queue-based scaling** is ideal for worker processes. Deploy workers as separate Container Apps that scale based on queue depth.
80+
81+
> [!TIP]
82+
> For production apps that must always be ready, set `min-replicas` to `1`. For development and staging environments, use `min-replicas: 0` to save costs.
83+
84+
## Cost comparison
85+
86+
| Scenario | Heroku (Standard-1X) | Azure Container Apps (Consumption) |
87+
| --- | --- | --- |
88+
| Idle app (24/7) | ~ $25/month per dyno | $0 (scaled to zero) |
89+
| Low-traffic app | ~ $25/month per dyno | ~ $1–5/month |
90+
| High-traffic app (10 instances) | ~ $250/month | Varies by actual CPU and memory use |
91+
| Monthly free grant | None | 180,000 vCPU-seconds + 2 million requests |
92+
93+
For detailed pricing, see [Azure Container Apps pricing](https://azure.microsoft.com/pricing/details/container-apps/).
94+
95+
## Workers and background jobs
96+
97+
If your Heroku app uses worker dynos (defined in a `Procfile`), deploy each worker type as a separate Container App within the same environment. Use queue-based scaling instead of a fixed instance count.
98+
99+
| Heroku pattern | Azure Container Apps pattern |
100+
| --- | --- |
101+
| `web` process type | Container App with HTTP ingress and HTTP-based scaling |
102+
| `worker` process type | Container App (no ingress) with queue-based scaling |
103+
| Scheduled tasks (Heroku Scheduler) | [Container Apps job](/azure/container-apps/jobs) with a cron schedule |
104+
| One-off tasks (`heroku run`) | [Container Apps job](/azure/container-apps/jobs) with manual trigger |
105+
106+
## Common pitfalls
107+
108+
Review these common issues before and during your migration to avoid delays.
109+
110+
| Pitfall | Symptom | Resolution |
111+
| --- | --- | --- |
112+
| **PORT environment variable** | App doesn't respond to requests. | Container Apps sets a `PORT` variable and expects your app to listen on it. If you hardcode a port, set `--target-port` to match when creating the container app. Most Heroku apps already read `PORT` from the environment and work without changes. |
113+
| **Ephemeral filesystem** | Files written at runtime disappear after restarts. | Like Heroku, Container Apps uses an ephemeral filesystem. For persistent files, [mount an Azure Files share](/azure/container-apps/storage-mounts). |
114+
| **Scaling misconfiguration** | Unexpected costs or poor performance under load. | Start with HTTP concurrency scaling for web apps and monitor with Azure Monitor. Avoid setting `max-replicas` too high before you understand your app's resource consumption. |
115+
| **Environment parity** | Configuration drift between dev, staging, and production. | Use infrastructure as code ([Bicep](/azure/azure-resource-manager/bicep/overview) or [Terraform](/azure/developer/terraform/overview)) to keep environments consistent. This approach replaces the consistency Heroku Pipelines provided. |
116+
| **Third-party services** | Unnecessary migration work for SaaS add-ons. | Many Heroku add-ons are standalone SaaS products (SendGrid, MongoDB Atlas, Elasticsearch). These services often continue to work from Container Apps — update the connection URL only. Only Heroku-managed services (Heroku Postgres, Heroku Redis, Heroku Kafka) require migration to Azure equivalents. |
117+
| **Cloud Build availability** | `az containerapp up --source` fails with `ManagedEnvironmentNotFound` or builder errors. | Cloud Build isn't available in all regions or for all language stacks. Fall back to the ACR-based approach: create a Dockerfile, build with `az acr build`, and deploy the image. See [Migrate an app from Heroku](migrate-heroku.md#3---deploy-your-app) for both approaches. |
118+
| **Secrets and env vars ordering** | Environment variables referencing secrets resolve as empty. | Set secrets with `az containerapp secret set` *before* referencing them in environment variables. Also note that setting secrets alone doesn't restart the app — you need `az containerapp update` to create a new revision. |
119+
| **Azure service provisioning times** | Migration takes longer than expected. | Azure managed services take longer to provision than Heroku add-ons. Azure Cache for Redis can take 10–20 minutes; Azure Database for PostgreSQL can take 5–10 minutes. Provision these services in parallel while deploying your app. |
120+
121+
## Next step
122+
123+
> [!div class="nextstepaction"]
124+
> [Migrate an app from Heroku to Azure Container Apps](migrate-heroku.md)

0 commit comments

Comments
 (0)