> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dbhost.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Direct database migrations

> Use a short-lived, verified TLS connection for schema migration tools while your app keeps PgBouncer.

When Direct migration connection is available on a managed database, request
access from its dashboard or with `dbhost databases migration-request`. Give
the exact public IP of your migration runner. DBHost first reserves the
request; access opens after an operator has applied the matching cloud and
host allowlists and verified the PostgreSQL TLS certificate. A reserved
request is not a working connection.

The active profile shows `migrate.dbhost.app:5432`, database name, a dedicated
migration username and expiry. Use `sslmode=verify-full` and the password
revealed by the owner in the dashboard or returned by
`dbhost databases migration-credentials <database-id> --show-secret` and the
owner-scoped API. Keep that password in your CI secret store; never
commit it or put it in a command URL. The migration login starts with the
database owner as its effective SQL role, so migration tools create objects
under the same owner as the rest of the managed database. It cannot create
roles or databases, and the admission allows only one migration job at a time
with at most two direct sessions. Pending requests wait for that single
active slot. Your application runtime URL stays on
PgBouncer at port 6432.

| Tool | Migration process | Important detail |
| - | - | - |
| Prisma Migrate v7 | Put the direct profile in `prisma.config.ts` `datasource.url`; keep your application adapter on its normal pooled URL. | `migrate deploy` and `resolve` use the migration URL. `migrate dev` may require a separate, precreated shadow database; this role has no `CREATEDB`. [Prisma configuration](https://www.prisma.io/docs/orm/v7/reference/prisma-config-reference) |
| Drizzle Kit | Point the migration-specific `drizzle.config.ts` `dbCredentials.url` to the direct profile. | `drizzle-kit migrate` owns its migration ledger. Serialize runners in CI. [Drizzle Kit migrate](https://orm.drizzle.team/docs/drizzle-kit-migrate) |
| Flyway | Set the migration process URL to the direct profile. | For `CREATE INDEX CONCURRENTLY`, set `flyway.postgresql.transactional.lock=false` and use a nontransactional migration. [Flyway lock setting](https://documentation.red-gate.com/flyway/reference/configuration/flyway-namespace/flyway-postgresql-namespace/flyway-postgresql-transactional-lock-setting) |
| Rails | Run `db:migrate` with the direct profile, separate from the app's pooled configuration. | Keep Active Record advisory locks enabled for migrations. Use `disable_ddl_transaction!` only when the migration requires nontransactional DDL. [Rails configuration](https://guides.rubyonrails.org/configuring.html) |
| Django | Run `manage.py migrate` against a direct database alias or migration-only settings. | PostgreSQL migrations are atomic by default. Set `atomic = False` for operations that cannot run in a transaction. Keep runtime cursor/pooling choices separate. [Django migrations](https://docs.djangoproject.com/en/6.0/topics/migrations/) |

Use one runner per database even when the role permits two connections. Do
not use a wildcard source IP or a dynamic CI egress address; use a runner
with stable public egress. Schema changes and logical backup/restore cannot
be promised as one consistent point while your own DDL is in flight.

To finish early, click **Revoke migration access** or run
`dbhost databases migration-revoke <database-id> --yes`. New logins stop and
existing migration sessions are disconnected. The operator then removes the
matching network rules. At expiry, DBHost also disables the role and drains
its sessions; status may show reconciliation until the exact rules and role
are removed. A second request waits until that cleanup is terminal.

If the API returns `FEATURE_NOT_AVAILABLE`, keep using your existing owner
connection for migrations. Direct migration access is released only after its
TLS and network checks have passed for your database.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.