Tutorial

Heroku to SnapDeploy Migration: A Step-by-Step Guide

SnapDeploy Team 2026-01-17 12 min read
herokumigrationdockerdeploymentguide

Heroku removed its free tier on November 28, 2022. Overnight, hundreds of thousands of hobby apps went offline. The platform that once had 13 million accounts lost the hobbyist and student demographic almost entirely — while Eco dynos ($5/month for a shared 1,000-hour pool) still sleep after 30 minutes and take 15-30 seconds to wake up.

If you're still on Heroku paying $5-25/month for a single dyno, or if you left and haven't found a permanent home yet, this guide walks you through a complete migration to SnapDeploy — with real Procfile-to-Dockerfile conversions, actual CLI commands, and an honest cost comparison.

What You're Leaving Behind (and What You're Not)

Here's what Heroku costs in 2026 for a typical small app:

Component Heroku Plan Monthly Cost
Web dyno (always-on) Basic $7
Postgres database Essential-0 (1 GB, 20 conn) $5
Redis cache Mini (25 MB, 20 conn) $3
Logging Papertrail (free tier) $0
Total $15/month ($180/year)

Need more power? A Standard-1x dyno ($25/mo) with Standard-0 Postgres ($50/mo) puts you at $75/month before you've added Redis or a worker dyno. And Heroku's Performance-M dyno is $250/month — for 2.5 GB RAM.

Step 1: Export Everything from Heroku

Before touching SnapDeploy, extract your Heroku configuration and data:

Export Environment Variables

# Export all config vars to a .env file
heroku config -s --app your-app-name > .env

# Review what you exported (remove Heroku-specific vars)
cat .env
# Remove these Heroku-specific vars — they won't work on SnapDeploy:
# DATABASE_URL (will use SnapDeploy's managed database instead)
# HEROKU_SLUG_COMMIT, HEROKU_SLUG_DESCRIPTION
# PAPERTRAIL_API_TOKEN (SnapDeploy has built-in logging)

Export Your Database

# Capture a fresh backup
heroku pg:backups:capture --app your-app-name

# Download the backup locally
heroku pg:backups:download --app your-app-name
# This creates a file called "latest.dump"

# If you need a SQL file instead:
pg_restore --verbose --no-acl --no-owner -f dump.sql latest.dump

Step 2: Convert Your Procfile to a Dockerfile

Heroku uses Procfiles and buildpacks. SnapDeploy uses Dockerfiles — and will auto-generate one if you don't have one. But if you want full control, here are the conversions for the four most common stacks:

Node.js (Express)

Heroku Procfile: web: node server.js

FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]

Python (Flask / Django)

Heroku Procfile: web: gunicorn app:app

FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "app:app"]

Java (Spring Boot)

Heroku Procfile: web: java -jar target/*.jar

FROM eclipse-temurin:17-jdk-alpine AS build
WORKDIR /app
COPY . .
RUN ./mvnw package -DskipTests

FROM eclipse-temurin:17-jre-alpine
WORKDIR /app
COPY --from=build /app/target/*.jar app.jar
EXPOSE 8080
CMD ["java", "-jar", "app.jar"]

Ruby (Rails)

Heroku Procfile: web: bundle exec puma

FROM ruby:3.3-slim
WORKDIR /app
COPY Gemfile Gemfile.lock ./
RUN bundle install --without development test
COPY . .
EXPOSE 3000
CMD ["bundle", "exec", "puma", "-C", "config/puma.rb"]

Important port note: Heroku dynamically assigns $PORT (usually 80). In your Dockerfile, bind to a specific port (3000, 8000, 8080) and SnapDeploy will auto-detect the correct port from your framework. If auto-detection gets it wrong, you can override it in the dashboard.

Step 3: Deploy on SnapDeploy

Once your code is on GitHub with a Dockerfile (or without — SnapDeploy auto-generates one):

  1. Sign up at snapdeploy.dev — no credit card required.
  2. Connect GitHub — Install the SnapDeploy GitHub App on your repository.
  3. Create a container — Name it, select your repo and branch (usually main).
  4. Add environment variables — Paste the vars from your .env export. SnapDeploy encrypts them at rest.
  5. Deploy — Build takes 2-3 minutes. Your app gets a your-app.snapdeploy.dev subdomain with free SSL.
  6. Enable auto-deploy — Every push to your branch triggers a new build automatically.

Step 4: Migrate Your Database

SnapDeploy offers managed database add-ons (PostgreSQL, MySQL, MongoDB) directly from the dashboard. To import your Heroku Postgres data:

# 1. Create a PostgreSQL add-on in SnapDeploy dashboard
#    You'll get a connection string like:
#    postgresql://user:[email protected]:5432/dbname

# 2. Restore your Heroku backup to the new database
pg_restore --verbose --no-acl --no-owner \
  -d "postgresql://user:[email protected]:5432/dbname" \
  latest.dump

# 3. Update your app's DATABASE_URL environment variable
#    in the SnapDeploy dashboard to point to the new database

Cost Comparison: Heroku vs SnapDeploy

Scenario Heroku SnapDeploy Annual Savings
Side project (sleep OK) $5/mo Eco (sleeps after 30 min, shared 1000 hr pool) $0 (sleeps after 15 min, ~60s wake) $60/year
Small API (always-on, 512 MB) $7/mo Basic dyno $12/mo Always-On -$60/year (Heroku cheaper)
Production app (1 GB, always-on) $25/mo Standard-1x $25/mo Always-On $0 (same price, better isolation)
Production app + Postgres + Redis $25 + $50 + $15 = $90/mo $25/mo + managed add-ons Varies by add-on tier
High-memory app (2.5 GB) $250/mo Performance-M $45/mo Always-On (4 GB) $2,460/year

Honest take: At the 512 MB tier, Heroku's $7/mo Basic dyno is cheaper than SnapDeploy's $12/mo. But Heroku's Basic dynos have no horizontal scaling, no preboot, and no metrics. SnapDeploy gives you AWS Fargate isolation, real-time CPU/memory monitoring, and auto-deploy from GitHub at every tier. The value gap widens significantly at 1 GB+ where Heroku's pricing escalates fast.

Common Migration Issues (and Fixes)

1. Port binding errors

Heroku injects $PORT automatically. If your app reads process.env.PORT, set the PORT environment variable in SnapDeploy (e.g., PORT=3000) or update your code to use a hardcoded port that matches your Dockerfile's EXPOSE.

2. Buildpack-specific behavior

Heroku buildpacks sometimes run post-compile scripts or inject environment variables. If your app depends on DYNO, STACK, or buildpack-specific hooks, remove those references. Docker gives you full control over the build process.

3. File system differences

Heroku has an ephemeral filesystem that resets on every deploy. SnapDeploy containers also have ephemeral storage, but you can use S3 or managed databases for persistent data — just like you should on Heroku.

4. Custom domains

On Heroku, custom domains require paid dynos and ACM certificates. On SnapDeploy, custom domains are unlimited and free on Always-On containers — add a CNAME record pointing to proxy.snapdeploy.dev and SSL is provisioned automatically via Let's Encrypt.

What You Gain After Migration

  • Container isolation: Each app runs in its own AWS Fargate task — no shared dynos, no noisy neighbors.
  • Free tier that stays free: Up to 4 containers with auto-sleep/wake, no credit card, 10 free deploys per day.
  • GPU compute: Heroku has no GPU option. SnapDeploy offers Tesla T4 (16 GB VRAM) at $0.50/hour for AI/ML workloads.
  • Real-time monitoring: CPU, memory, and deployment logs in the dashboard — no addon required.
  • Security scanning: Automated vulnerability scanning with Trivy, Semgrep, OWASP Dependency Check, and Gitleaks — built into the platform.
  • Auto-deploy on push: Push to your branch, SnapDeploy builds and deploys automatically. No Heroku CLI needed.

Ready to Deploy?

Deploy free. 10 deploys a day, no credit card.

Get DevOps Tips & Updates

Container deployment guides, platform updates, and DevOps best practices. No spam.

Unsubscribe anytime. We respect your privacy.

More Articles