# Migrate from Heroku

> Move your app and Postgres add-on from Heroku to Ownkube. Map your Procfile to Web, Worker, and Job deployments, copy config vars, and cut over with no rewrite.

Moving from [Heroku](https://www.heroku.com/) to Ownkube is mostly mapping your `Procfile` process types to Ownkube deployments, re-creating your database, and copying your config vars. There's no rewrite: if it deploys on Heroku, it deploys on Ownkube. This guide walks the cutover, including the database backup and restore.

For a side-by-side of the two platforms, see [Ownkube vs Heroku](/docs/compare/heroku).

## What moves

| On Heroku | On Ownkube |
|---|---|
| `web` process in the Procfile | A **Web** deployment from the same repo |
| `worker` process in the Procfile | A **Worker** deployment |
| Heroku Scheduler task | A **Job** deployment with a schedule |
| Heroku Postgres add-on | A managed **PostgreSQL** database |
| Config vars | Environment variables on the deployment |
| Dyno | A deployment, metered per minute on actual CPU and memory instead of a fixed dyno size |

## Migrate your app

1. **Connect your repo**

   Connect your GitHub or GitLab account so Ownkube can build from the same repo. See [Registries](/docs/features/registries).

2. **Map your Procfile to deployments**

   Create one Ownkube deployment per process type in your `Procfile`. A `web: ...` line becomes a **Web** deployment with the port your app listens on; a `worker: ...` line becomes a **Worker** deployment; anything you run through Heroku Scheduler becomes a **Job** with a schedule. Ownkube builds from source, or uses your `Dockerfile` if you have one.

3. **Copy your config vars**

   Bring over the values from `heroku config`. Add them as `KEY=value` pairs and flip **Secret** on the sensitive ones. See [Environment variables](/docs/guides/environment-variables).

## Migrate your database

1. **Create a managed Postgres database**

   Add a **Database** (PostgreSQL) in the same [environment](/docs/features/environments) as your app. Ownkube generates credentials and injects `DATABASE_URL` into your app. See [Databases](/docs/features/databases).

2. **Dump from Heroku**

   Using your Heroku app's database URL, dump the data:

   ```bash
   pg_dump "$(heroku config:get DATABASE_URL -a your-app-name)" --no-owner --no-privileges -Fc -f dump.pgc
   ```

3. **Restore into Ownkube**

   Turn on [public access](/docs/features/databases#public-access) for the new database (temporarily), then restore into it with TLS verification on:

   ```bash
   pg_restore --no-owner --no-privileges \
     -d "postgresql://user:pass@db-yourname.ownkube.app:5432/app?sslmode=verify-full&sslnegotiation=direct" \
     dump.pgc
   ```

   Turn public access back off when the restore finishes. For production traffic, connect from inside the network.

Do a trial run into a development environment first, verify row counts and a few queries, then repeat the dump/restore during a short maintenance window for the real cutover so you don't lose writes.

## Cut over

1. **Verify on Ownkube.** Open the generated hostname, exercise the app, and confirm it reads and writes the migrated database.
2. **Move your domain.** Point your [custom domain](/docs/guides/custom-domain) at the Ownkube deployment. TLS is provisioned and renewed automatically.
3. **Decommission Heroku** once traffic is served from Ownkube and you've confirmed a clean window.

## Want your own cloud later?

You can start on Ownkube Compute and, if you ever want your own data boundary or your own bill, [connect an AWS account](/docs/guides/connect-aws) and run the same app in your own VPC with no second migration. See [Clusters](/docs/features/clusters).

- [Ownkube vs Heroku](/docs/compare/heroku)
- [Deploy a Next.js app](/docs/deploy/nextjs)
- [Pricing](/docs/configuration/pricing)
- [On the blog: a Heroku alternative in your own AWS account](/blog/heroku-alternative-in-your-own-aws-account)

---

**Don't see a feature you need?** Email [support@ownkube.io](mailto:support@ownkube.io?subject=Feature%20request). Ownkube is shaped by the teams using it and we ship what our users ask for.
