← Back to Blog
Engineering··10 min read

How We Migrated a Startup from Heroku to AWS in a Weekend

HN Reference: HN discussion on Heroku's pricing changes and migration stories (Sep 2023)

When Heroku eliminated their free tier and raised prices, we helped a startup client migrate their production SaaS to AWS over a weekend. Here's exactly how we did it.

The Situation

  • App: Node.js API + React frontend + PostgreSQL + Redis
  • Traffic: ~50K requests/day
  • Users: ~2,000 active
  • Constraint: Zero downtime allowed
  • Budget: Keep costs under $200/month (they were paying $350 on Heroku)

The Plan

We broke the migration into phases:

Phase 1: Infrastructure Setup (Saturday Morning)

Set up the AWS infrastructure before touching production:

- ECS Fargate for the API (2 tasks, auto-scaling)
- RDS PostgreSQL (db.t3.micro, single-AZ for cost)
- ElastiCache Redis (cache.t3.micro)
- S3 + CloudFront for the frontend
- ALB for load balancing

Total time: 3 hours. We used Terraform so it was reproducible.

Phase 2: Database Migration (Saturday Afternoon)

The database was the riskiest part. Here's our approach:

  1. Set up a read replica from Heroku's PostgreSQL to RDS
  2. Let the replica sync for 4 hours
  3. Verified data integrity (row counts, spot checks)
  4. Prepared the cutover script

Phase 3: Application Deployment (Saturday Evening)

  1. Deployed the app to ECS pointing to the new RDS instance
  2. Ran the test suite against the new environment
  3. Fixed environment-specific issues (Heroku config vars → AWS Secrets Manager)
  4. Verified all integrations (Stripe, SendGrid, etc.)

Phase 4: Cutover (Sunday Morning)

This was the critical moment:

  1. Put the Heroku app in maintenance mode (5-minute window)
  2. Ran the final database sync (delta only)
  3. Switched DNS from Heroku to the ALB
  4. Verified the new deployment
  5. Took Heroku app offline

Total downtime: 4 minutes.

The Tools

  • Terraform: Infrastructure as code
  • pg_dump/pg_restore: Database migration
  • AWS CLI: Automation scripts
  • Datadog: Monitoring during and after migration
  • PagerDuty: Alerting for any issues

What Went Wrong

SSL certificate issues. Heroku managed SSL automatically. On AWS, we had to set up ACM certificates and wait for DNS validation. Lesson: start this process days before the migration.

Environment variables. Heroku's config vars don't map 1:1 to AWS Secrets Manager. We missed two config values and had a 10-minute debugging session.

Redis connection strings. ElastiCache Redis uses VPC-internal endpoints. We had to update every reference to the Redis URL.

The Results

  • Cost: $147/month (down from $350)
  • Performance: 20% faster response times (ECS + optimized networking)
  • Reliability: Auto-scaling handled traffic spikes that would have degraded on Heroku
  • Control: Full access to infrastructure, logs, and metrics

Advice for Others

  1. Practice the migration first. We did a dry run on Friday night. It caught 3 issues we fixed before the real migration.
  2. Have a rollback plan. We kept the Heroku app ready to reactivate for 72 hours.
  3. Communicate with users. We sent an email about the planned maintenance window. Users appreciate transparency.
  4. Monitor aggressively after. We watched dashboards for 48 hours post-migration.

Migrations are scary but manageable with proper planning. The biggest risk isn't technical — it's underestimating the complexity.

AWSMigrationInfrastructureDevOpsCase Study