← Blog

Salir de Heroku Postgres sin perder datos

Railyard

7 de abril de 2026 · 9 min de lectura

Sigue esto en tu propio servidor. Empieza gratis, sin tarjeta

Heroku dejó de ofrecer un nivel gratuito de Postgres hace un tiempo, y el plan pago más barato que queda, Essential-0, igual te limita a 1 GB de almacenamiento, 20 conexiones y un tope de 4.000 tablas por 5 dólares al mes. Eso está bien para una aplicación de prueba. No está bien para nada que haya crecido de verdad, y no está bien por el precio, una vez que lo comparas con correr la misma base de datos en otro lado. Lo que frena a la mayoría no es la decisión, es el miedo a dañar los datos en el camino: perder filas, restaurar con la codificación equivocada, o hacer el cambio antes de que la base de datos nueva esté realmente lista. Al final de esta guía tendrás una copia completa y verificada de tus datos de Heroku Postgres corriendo en una base de datos nueva, tu aplicación apuntando a ella, y la antigua todavía ahí como respaldo mientras confirmas que todo está bien.

Lo que necesitas

  • El CLI de Heroku instalado y con sesión iniciada (heroku login), con acceso a la aplicación cuya base de datos vas a migrar.
  • Un servidor Postgres de destino. Esta guía usa un Basic Droplet de DigitalOcean a 6 USD/mes (1 vCPU, 1 GiB de RAM, 25 GB SSD) corriendo Postgres en Docker, que le queda cómodo a una base de datos que vivía en un plan Heroku Essential-0 de 1 GB. Usa una máquina más grande si tus datos son más voluminosos.
  • pg_dump y pg_restore en tu máquina, con una versión igual o más reciente que la de Postgres en tu base de datos de Heroku. Postgres.app o el paquete postgresql-client de tu sistema operativo te da ambos.
  • Una ventana de mantenimiento no es estrictamente necesaria, pero ayuda elegir un momento tranquilo, ya que vas a volver a apuntar DATABASE_URL a mitad de camino.
  • Entre 10 y 15 minutos, más si tu base de datos es grande o tu conexión es lenta.

Paso 1: Captura un respaldo nuevo en Heroku

No restaures desde el respaldo automático que Heroku tenga por ahí. Toma uno ahora mismo, para saber exactamente desde qué momento estás migrando.

heroku pg:backups:capture --app your-app-name

Esto dispara un respaldo nuevo del lado de Heroku, en el formato de dump comprimido personalizado de Postgres. Puede tardar desde unos segundos hasta varios minutos según el tamaño de tu base de datos. Revisa el avance con:

heroku pg:backups --app your-app-name

Deberías ver una fila para el respaldo que acabas de capturar, con estado Completed y un tamaño parecido al que esperarías para tu base de datos. Si todavía dice Pending o Running, espera y vuelve a revisar antes de continuar: un respaldo que sigue capturándose fallará al descargarlo.

Paso 2: Descarga el respaldo

Una vez que termine la captura, bájalo a tu máquina:

heroku pg:backups:download --app your-app-name

Esto guarda un archivo llamado latest.dump (o el ID del respaldo específico si pasaste uno) en tu directorio actual. Si prefieres entregarle el archivo a otra cosa en vez de descargarlo tú mismo, heroku pg:backups:url --app your-app-name te da una URL pública temporal hacia el mismo dump, válida por cerca de una hora.

Deberías ver un archivo latest.dump en el disco, con un tamaño en el mismo rango que el que reportó heroku pg:backups.

Paso 3: Prepara la base de datos Postgres de destino

Si te estás mudando a una instancia Postgres autoalojada en lugar de a otro proveedor administrado, un archivo pequeño de Docker Compose te da una base de datos corriendo rápido:

services:
  postgres:
    image: postgres:16.4-alpine
    restart: unless-stopped
    environment:
      POSTGRES_USER: appuser
      POSTGRES_PASSWORD: change-me
      POSTGRES_DB: appdb
    volumes:
      - pgdata:/var/lib/postgresql/data
    ports:
      - "5432:5432"

volumes:
  pgdata:

Levántalo con:

docker compose up -d

Deberías ver el contenedor corriendo (docker compose ps) y poder conectarte con psql -h your-server-ip -U appuser -d appdb. Si en cambio estás apuntando a un Postgres administrado de otro proveedor, asegúrate de tener su cadena de conexión y de que acepte conexiones desde tu IP antes de seguir.

Paso 4: Restaura el dump en la base de datos nueva

pg_restore lee el mismo formato personalizado en el que ya viene el respaldo de Heroku, así que no hay paso de conversión:

pg_restore --verbose --clean --no-acl --no-owner \
  -h your-server-ip -U appuser -d appdb latest.dump

--clean elimina cualquier objeto en conflicto antes de volverlo a crear, lo cual importa si ya corriste migraciones contra una base de datos vacía y esta tiene tablas que de otro modo chocarían con la restauración. --no-acl y --no-owner omiten referencias de roles y permisos propias de Heroku que no existen en tu nuevo servidor y que de otra forma arrojarían errores que puedes ignorar sin problema.

Deberías ver desfilar un flujo largo de líneas CREATE TABLE, CREATE INDEX y COPY sin errores fatales al final. Unas pocas advertencias de already exists o does not exist, skipping son normales y no indican que algo haya salido mal.

Paso 5: Verifica que los datos realmente coincidan

Antes de tocar DATABASE_URL, revisa que lo que llegó esté completo. Compara el conteo de filas tabla por tabla entre Heroku y la base de datos nueva:

SELECT schemaname, relname, n_live_tup
FROM pg_stat_user_tables
ORDER BY relname;

Corre esto contra ambas bases de datos (conéctate a Heroku con heroku pg:psql --app your-app-name) y compara los resultados. Para todo lo que tu aplicación trate como importante en lo financiero o legal, revisa puntualmente algunas filas específicas por clave primaria en lugar de confiar solo en los conteos.

Deberías ver conteos de filas que coinciden para cada tabla, sin ninguna tabla presente de un lado y ausente del otro.

Paso 6: Apunta tu aplicación a la base de datos nueva

Una vez que confirmes que los datos coinciden, actualiza dondequiera que tengas DATABASE_URL, tu archivo .env, las variables de configuración de tu nuevo proveedor, tu gestor de secretos, hacia la nueva cadena de conexión, y vuelve a desplegar. Si tu destino necesita sslmode=require o algo similar, configúralo ahora en la cadena de conexión en lugar de descubrirlo en producción.

Deberías ver que el siguiente despliegue de tu aplicación se complete con éxito y lea/escriba contra la base de datos nueva. Vigila tus registros de errores durante unos minutos después del despliegue por cualquier cosa relacionada con la conexión.

Paso 7: Deja Heroku activo un momento, luego retíralo

No borres la aplicación de Heroku ni reduzcas su base de datos apenas el cambio se vea bien. Déjala corriendo, sin tocarla, durante un día o dos como respaldo al que volver si aparece algo que tu verificación de conteo de filas no detectó. Una vez que estés seguro, reduce el dyno y la base de datos de Heroku, y luego retíralos.

El atajo: hazlo con Railyard

Todo lo anterior es el camino manual, útil de conocer porque es lo que realmente ocurre por debajo de cualquier herramienta que diga hacer esto por ti. Railyard tiene dos formas de saltarte la mayor parte.

Si estás moviendo toda la aplicación, no solo la base de datos, Applications → Import lee tu aplicación directamente desde Heroku usando un token de API: las variables de configuración, la formación (tus tipos de proceso y sus cantidades), y cualquier add-on de Postgres, Redis, MySQL o Memcached se transfieren automáticamente, junto con los dominios personalizados. Tú agregas la URL de Git por tu cuenta, ya que la API de Heroku no comparte tu repositorio. La importación de Heroku está actualmente en beta, es decir que todavía no se ha probado contra suficientes cuentas reales para darla por completamente verificada, así que Railyard te muestra el plan para tu aplicación específica antes de hacer nada, y lo revisas antes de confirmar. La base de datos en sí se trae transmitiendo un dump directamente desde tu DATABASE_URL de Heroku hacia la nueva base de datos administrada, y la aplicación vieja de Heroku sigue sirviendo tráfico hasta que la nueva URL responda y tú mismo muevas el DNS.

Si solo quieres mover la base de datos y vas a mantener tu aplicación y tu flujo de despliegue donde están, el flujo independiente Import data hace por su cuenta esa mitad del trabajo: pega tu URL de conexión de Heroku Postgres (la misma que te da heroku config:get DATABASE_URL), y Railyard extrae los datos directamente desde ahí. Primero respalda lo que haya actualmente en la base de datos de destino, así que si la importación falla o la cancelas a mitad de camino, tus datos existentes se restauran automáticamente en lugar de quedar a medio sobrescribir. Si eliges desplegar después de que termine la importación, corre las migraciones de tu aplicación como último paso.

En cualquiera de los dos casos, la salida de heroku config -s se pega directamente en Variables → Bulk import de Railyard, así que tus variables de entorno no necesitan volver a escribirse a mano.

Los detalles completos de ambos flujos: Importar desde otra plataforma y Bases de datos y respaldos. Si todavía estás decidiendo si migrar o no, la guía completa está en Migrar desde Heroku, y nuestro verificador de factura de Heroku te dirá aproximadamente cuánto estás pagando hoy comparado con otras opciones.

Solución de problemas

heroku: command not found o errores de autenticación. Asegúrate de que el CLI esté instalado y vuelve a correr heroku login; una sesión caducada o expirada se manifiesta como un error de permisos en comandos que por lo demás se ven correctos.

La descarga del respaldo falla o devuelve un archivo vacío. Esto casi siempre significa que la captura del Paso 1 no había terminado realmente. Vuelve a revisar heroku pg:backups --app your-app-name y espera a Completed antes de descargar o pedir una URL.

pg_restore da errores sobre objetos que ya existen. Esto pasa cuando restauras en una base de datos que ya tiene tablas en conflicto, normalmente una donde ya corrieron migraciones. Usa --clean como se muestra arriba, o restaura en una base de datos realmente vacía y corre tus propias migraciones en lugar del esquema del dump.

Errores de conexión SSL o sslmode. Heroku Postgres exige una conexión SSL para el acceso directo con pg_dump/psql; si estás haciendo el dump directamente desde Heroku en lugar de desde un archivo de respaldo descargado, agrega ?sslmode=require a la cadena de conexión. Tu base de datos de destino puede tener el problema contrario, rechazando el SSL por completo en una instalación local nueva, en cuyo caso quita el parámetro para ese lado.

Tu aplicación sigue escribiendo en la base de datos vieja después del cambio. Esto casi siempre es un DATABASE_URL en caché, un valor del gestor de secretos que no se volvió a desplegar realmente, o un worker en segundo plano que no se reinició junto con el proceso web. Revisa cada tipo de proceso por separado, no solo el que sirve el tráfico HTTP.

Preguntas frecuentes

¿Esto causa downtime? No si sigues el orden de arriba. La aplicación de Heroku sigue sirviendo tráfico durante el respaldo, la restauración y la verificación; el único momento que realmente importa es cuando cambias DATABASE_URL, típicamente un solo redespliegue.

¿Qué pasa con mi aplicación de Heroku mientras migro? Nada, sigue corriendo exactamente igual que antes. La captura del respaldo lee desde un proceso tipo réplica y no bloquea tus tablas de producción.

¿Puedo migrar sin el CLI de Heroku? Solo parcialmente. Puedes obtener una cadena de conexión desde las Config Vars de tu aplicación en el panel de Heroku y correr pg_dump directamente contra ella, pero capturar y descargar un respaldo específicamente requiere el CLI (o que Railyard extraiga directamente desde la URL en vivo, lo cual no necesita ningún CLI).

¿Necesito que las versiones de Postgres coincidan exactamente? No, pero tu destino debería ser de la misma versión mayor o más reciente. Restaurar un dump de Heroku Postgres más reciente en un destino más antiguo puede fallar en funciones que todavía no existían en la versión anterior.

¿Y si mi base de datos es demasiado grande para un ciclo rápido de respaldo y restauración? El proceso es el mismo, solo toma más tiempo. Reserva más tiempo para los Pasos 1 y 4 en particular, y considera correr la restauración en una máquina con más RAM temporalmente si pg_restore va lento.

Sin importar el camino que elijas, manual o con Railyard, la disciplina que realmente protege tus datos es la misma: captura antes de tocar nada, verifica antes de hacer el cambio, y no borres la copia vieja hasta que hayas tenido tiempo de estar seguro.

Por qué eligen Railyard para esto

  • Tu propia cuenta en la nube. Despliega en DigitalOcean, Hetzner, Vultr, AWS, OVHcloud, o cualquier servidor Linux por SSH, facturado directamente por tu proveedor, sin márgenes adicionales.
  • Un precio fijo por equipo. El plan Free es gratis para siempre: un servidor más un servidor de base de datos, tres apps, sin tarjeta. Pro cuesta $19 al mes por hasta cinco servidores y apps ilimitadas. Team cuesta $49 al mes con servidores ilimitados. Sin cargos por app, por despliegue, por asiento ni por gigabyte.
  • Plantillas de un clic. Despliega apps de código abierto, como bases de datos, analítica y herramientas de desarrollo, en tu propio servidor con un clic.
  • Bases de datos administradas. Postgres, MySQL y Redis, con copias de seguridad programadas y verificadas por restauración, y recuperación a un punto en el tiempo.
  • Despliegue con git push. Despliega desde GitHub, GitLab o la CLI, con HTTPS automático y lanzamientos sin tiempo de inactividad.

Sáltate el dump y la restauración

Pega tu URL de conexión de Heroku Postgres en Railyard: la plataforma respalda, transmite los datos y migra por ti.

Plan gratis, sin tarjeta, y 14 días de Pro para cada equipo nuevo. Un precio fijo por equipo.