Migrate from Heroku
to AWS
Migrating from Heroku to AWS trades PaaS simplicity for IaaS flexibility, requiring teams to take ownership of infrastructure concerns that Heroku previously abstracted—including container orchestration, database administration, SSL certificate management, and deployment pipelines. The migration is justified when Heroku's dyno-based scaling model, add-on cost premiums, or platform constraints become limiting factors, but teams must budget for significant operational maturity investment.
When Heroku stops working
Heroku stops being viable when your application's scaling requirements exceed what the dyno model efficiently supports—Performance-L dynos cap at 14GB RAM and vertical scaling beyond that requires architectural workarounds. Heroku's pricing becomes prohibitive at scale: a Performance-L dyno costs $500/month while equivalent EC2 compute is available for under $150/month, and add-on markups for services like Heroku Postgres, Redis, and Kafka can be 2-5x the cost of equivalent AWS managed services. The platform's 30-second request timeout, 512MB slug size limit, and ephemeral filesystem create architectural constraints that force increasingly complex workarounds as applications grow. Teams outgrow Heroku when they need fine-grained networking control (VPC peering, private subnets, custom DNS), multi-region deployment, or compliance certifications that Heroku's shared-tenancy Shield offering cannot satisfy. The lack of infrastructure-as-code support beyond basic Terraform provider coverage makes environment reproducibility and disaster recovery difficult at enterprise scale.
What AWS unlocks
AWS unlocks complete infrastructure control, enabling custom VPC architectures with private subnets, NAT gateways, and VPC endpoints that provide network isolation impossible on Heroku. Container orchestration via ECS Fargate or EKS eliminates dyno constraints—containers can be sized precisely to workload requirements with CPU and memory independently configurable, autoscaling policies based on custom CloudWatch metrics, and no slug size limitations. RDS provides database management with automated backups, read replicas, Multi-AZ failover, and Performance Insights that exceed Heroku Postgres capabilities at a fraction of the cost for equivalent compute. Lambda and API Gateway enable serverless patterns for bursty workloads that would require expensive always-on dynos on Heroku. AWS's breadth of services—Step Functions for workflow orchestration, SQS/SNS for messaging, ElastiCache for caching, CloudFront for CDN—replaces Heroku add-ons with first-party managed services that have better SLAs, more configuration options, and lower costs.
Who should not migrate
Small teams and startups that value development velocity over infrastructure control should stay on Heroku, especially if their monthly Heroku spend is under $1,000 and the add-on ecosystem meets their needs. Teams without dedicated DevOps or platform engineering expertise will struggle with the operational complexity increase—managing ECS task definitions, ALB configurations, security group rules, IAM policies, and CloudWatch alarms requires skills that Heroku's platform abstracts entirely. Organizations running simple web applications with predictable traffic patterns and straightforward scaling needs (web + worker + database) get diminishing returns from AWS's flexibility since Heroku handles these patterns well. Teams in rapid prototyping phases where deployment speed matters more than cost efficiency should remain on Heroku until their product-market fit is established. If your application relies heavily on Heroku-specific features like Review Apps for pull request environments, you'll need to build equivalent functionality using AWS CodePipeline or third-party tools, which adds migration scope.
What usually goes wrong
The most common failure is underestimating the operational complexity increase. Teams accustomed to `git push heroku main` deploying their application are unprepared for building and maintaining CI/CD pipelines, container image builds, ECS service definitions, and blue-green deployment orchestration. Database migrations from Heroku Postgres to RDS seem straightforward but fail when applications depend on Heroku-specific features like `pg:pull` for local development, follower databases for read scaling, or credential rotation through Heroku's attachment model. Teams often try to replicate Heroku's Procfile-based process model directly in ECS without considering that each process type (web, worker, clock) should be an independent ECS service with its own scaling policy. Buildpack-to-Dockerfile conversion surfaces hidden dependencies that buildpacks silently resolved—specific system libraries, build-time vs runtime dependency separation, and asset compilation pipelines. The loss of Heroku's add-on marketplace means teams must individually set up, configure, and maintain each supporting service (logging, monitoring, email, search) as separate AWS services or third-party integrations, multiplying operational surface area.
Risk Matrix: Heroku to AWS
Heroku Postgres uses specific PostgreSQL extensions and configurations that may differ from RDS defaults. Applications often depend on Heroku's database credential rotation mechanism, follower database promotion workflow, and the heroku pg:backups system. Large databases cannot be migrated with pg_dump/pg_restore within acceptable downtime windows.
Use AWS DMS for continuous replication to minimize cutover downtime. Validate PostgreSQL extension compatibility between Heroku's PostgreSQL version and the target RDS version before migration. Test credential management by updating applications to use AWS Secrets Manager with rotation lambdas. Perform a full migration rehearsal with production-scale data and measure actual downtime.
Heroku buildpacks automatically detect and install language runtimes, system dependencies, and build tools. Converting to Dockerfiles requires explicitly specifying every dependency, and subtle differences in runtime versions, system libraries, or environment variables cause application behavior changes. Node.js buildpacks set specific memory flags, Python buildpacks configure pip caching, and Ruby buildpacks manage native extension compilation—all silently.
Use Cloud Native Buildpacks (pack build) as an intermediate step to generate container images from existing buildpack configuration before writing custom Dockerfiles. Compare the buildpack-generated image's installed packages against the Dockerfile-based image. Run application test suites against both environments and compare results. Pin exact runtime versions in Dockerfiles matching current Heroku stack versions.
Heroku abstracts away networking, SSL, load balancing, container orchestration, log aggregation, and deployment pipelines. Moving to AWS exposes all of these as explicit responsibilities. Teams often discover they need to manage 15-20 AWS services to replicate what Heroku provided as a single platform, and each service has its own configuration, monitoring, and failure modes.
Start with AWS App Runner or ECS Fargate to minimize infrastructure management overhead. Build infrastructure using Terraform or CDK from day one—never click-ops in the console. Invest in a comprehensive monitoring stack (CloudWatch, X-Ray, or third-party APM) before migrating production traffic. Consider a graduated migration where non-critical services move first to build team competence.
Teams catalog their primary add-ons (Postgres, Redis, Elasticsearch) but miss secondary add-ons like SendGrid for email, Papertrail for logging, Scout APM for monitoring, or Scheduler for cron jobs. Each add-on replacement requires individual AWS service setup, IAM permissions, VPC networking, and application configuration updates. Some add-ons have no direct AWS equivalent.
Export the complete Heroku add-on inventory using `heroku addons --all` for every application before migration planning. Map each add-on to its AWS equivalent or third-party replacement with configuration requirements documented. Migrate add-on replacements in dependency order—logging and monitoring first, then databases, then application-level services. Verify each replacement with integration tests before production cutover.
Heroku's git-push deployment model, automatic slug compilation, release phase execution, and Review Apps for pull requests must be completely rebuilt. Teams underestimate the complexity of building equivalent container build pipelines, image registries, deployment orchestration, and preview environment provisioning. GitHub integration that triggered Heroku deployments needs replacement with CodePipeline, GitHub Actions, or similar.
Build the CI/CD pipeline as the first migration workstream, not an afterthought. Use GitHub Actions or AWS CodePipeline to build container images, push to ECR, and deploy to ECS with blue-green deployment. Implement preview environments using ECS service discovery or AWS Copilot environments to replace Review Apps. Test the complete pipeline with a non-critical application before migrating production workloads.
What Must Not Change During This Migration
Every Heroku add-on must have a configured and tested AWS equivalent or third-party replacement with verified application connectivity before any production migration begins
Database migration must achieve zero data loss verified through row counts, checksum comparison, and application-level read validation on the target RDS instance before cutover
Container images must produce identical application behavior to Heroku slugs, validated through automated test suites run against both environments with results compared
CI/CD pipeline must support automated deployments with rollback capability equivalent to or better than Heroku's release management before production traffic is migrated
Monitoring, logging, and alerting coverage on AWS must match or exceed Heroku's built-in observability before decommissioning any Heroku application
Migration Process: Heroku to AWS
Application inventory and dependency mapping
Catalog every Heroku application, its dyno formation (web, worker, clock process types), attached add-ons with their plans and configurations, environment variables (config vars), and custom domains with SSL certificates. Document inter-application dependencies and any Heroku-specific features in use: Review Apps, Heroku CI, Pipelines (staging/production promotion), release phase commands, and Procfile process types. Map each Heroku add-on to its AWS equivalent service with pricing comparison.
Infrastructure foundation and networking
Deploy a VPC with public and private subnets across multiple availability zones using Terraform or CDK. Configure ALB with SSL certificates from ACM for each application's custom domains. Set up ECR for container image storage. Deploy RDS PostgreSQL instances in private subnets with security groups allowing access only from application subnets. Configure ElastiCache Redis clusters to replace Heroku Redis add-ons. Set up CloudWatch log groups, metric alarms, and SNS notification topics to replace Heroku's built-in logging and monitoring.
Service mapping and containerization
Convert each Heroku application's buildpack-based build into a Dockerfile, starting with Cloud Native Buildpacks for compatibility and then optimizing with custom multi-stage Dockerfiles. Translate Procfile process types into separate ECS task definitions—each process type becomes an independent ECS service with its own scaling policy, health check, and resource allocation. Map Heroku config vars to AWS Systems Manager Parameter Store or Secrets Manager entries. Replace Heroku Scheduler with EventBridge Scheduler rules triggering ECS RunTask or Lambda functions. Configure ECS service discovery for inter-service communication that previously used Heroku internal routing.
Parallel deployment and data migration
Deploy ECS services alongside running Heroku applications with identical application code deployed to both platforms. Migrate Heroku Postgres databases to RDS using AWS DMS with continuous replication to minimize cutover window. Replicate Heroku Redis data to ElastiCache using redis-cli or AWS DMS. Deploy the CI/CD pipeline using GitHub Actions or CodePipeline with automated image builds, ECR pushes, and ECS rolling deployments. Run integration and load tests against AWS-hosted applications to validate feature parity and performance characteristics.
Traffic migration and DNS cutover
Configure Route 53 hosted zones for all custom domains currently pointing to Heroku's DNS targets. Perform DNS cutover for non-critical applications first to validate the migration pattern. For critical applications, use weighted DNS routing to shift traffic incrementally: 10% to AWS initially with monitoring for error rate and latency regressions, then 50%, then 100%. Execute final database cutover during a maintenance window—stop Heroku application, wait for DMS replication lag to reach zero, promote RDS as primary, update application configuration, and start ECS services. Verify all webhook endpoints and external integrations are functioning.
Verification, optimization, and Heroku decommission
Run comprehensive application validation including all integration test suites, synthetic monitoring checks, and business-critical user journey tests against AWS-hosted applications. Verify logging pipeline completeness by comparing CloudWatch log output with historical Heroku log drain data. Validate backup and disaster recovery procedures—test RDS snapshot restoration, ECS service redeployment from scratch, and complete environment rebuild from infrastructure-as-code. Optimize costs by rightsizing ECS task definitions using Container Insights metrics, configuring auto-scaling policies based on actual traffic patterns, and purchasing Savings Plans for stable baseline compute. Decommission Heroku applications and add-ons after a 2-week soak period, canceling Heroku team/enterprise subscriptions last.
How This Migration Changes at Scale
Application runs more than 20 Heroku dynos across multiple process types
ECS service architecture becomes complex with multiple task definitions, auto-scaling policies, and service discovery configurations. Consider EKS if the team has Kubernetes experience, as Helm charts can standardize deployment patterns across many services. Budget 2-3 weeks of dedicated platform engineering per distinct process type to properly configure task definitions, health checks, and scaling policies.
Heroku Postgres database exceeds 100GB with high write throughput
Database migration cannot use pg_dump/pg_restore within acceptable downtime windows. AWS DMS continuous replication becomes mandatory, and the cutover window must be carefully planned around write quiescence. Consider Aurora PostgreSQL instead of standard RDS for its faster replication and failover capabilities. Budget 2-4 weeks for database migration including rehearsals with production-scale data.
More than 10 Heroku add-ons are in use across the application portfolio
Add-on replacement becomes a significant workstream requiring individual migration plans for each service. Prioritize add-ons by criticality: databases and caching first, then monitoring and logging, then application-level services like email and search. Some add-ons (like Heroku Connect for Salesforce sync) have no direct AWS equivalent and require custom integration development. Budget 1-2 weeks per complex add-on replacement.
Team relies heavily on Heroku Review Apps for pull request preview environments
Replicating Review App functionality on AWS requires building a custom CI/CD workflow that provisions temporary ECS services, databases, and DNS entries for each pull request. This is a non-trivial engineering effort—consider AWS Copilot environments, Vercel/Netlify for frontend preview, or third-party tools like Release or Qovery. Budget 3-4 weeks to build and stabilize PR preview infrastructure.
Related Migration Paths
Organizations migrating multiple platforms to AWS can apply identity and networking patterns from the Azure-to-AWS path while using Heroku-to-AWS patterns for PaaS workloads, consolidating both migration efforts.
Heroku applications commonly expose REST APIs that can be wrapped with MCP tool interfaces during or after the AWS migration, modernizing the API layer alongside the infrastructure.
Heroku migrations often coincide with broader modernization efforts—decomposing monolithic Heroku applications into microservices on ECS/EKS follows patterns covered in this legacy-to-modern migration path.
Related Analysis
If you're evaluating a migration from Heroku to AWS, the first step is validating risk, scope, and invariants before any build work begins.