Saltar al contenido

Backups

Prueba tu backup de Supabase antes del día que lo necesites

Cómo probar tu backup de Supabase: restaurarlo en un proyecto de prueba, contar filas, iniciar sesión y buscar la línea que le falta a un archivo cortado.

Vlad Tkachenko17 min de lectura
Una fila de archivos de backup sellados e idénticos, el primero iluminado, junto a una base de datos vacía y punteada que espera uno.

En resumen

  • Para probar un backup de Supabase, restáuralo en un proyecto que no importe, compara sus números de filas con la base de datos en producción e inicia sesión como tú. Solo una restauración distingue un archivo bueno de uno roto.
  • Cortamos un dump a mitad de una tabla y lo cargamos con las opciones que recomienda Supabase. psql terminó sin ningún error, y las tablas volvieron incompletas.
  • Haz el simulacro una vez ahora, luego cada tres meses y después de cualquier cambio en cómo se hace el backup, y apunta la fecha cada vez.

En algún sitio hay un archivo con tu base de datos dentro. Una GitHub Action escribe uno cada noche, o ejecutaste una vez los tres comandos de backup de Supabase, o tu plan hace copias diarias. Tiene el nombre correcto y más o menos el tamaño que esperarías. Nadie lo ha abierto nunca.

Esta es la parte que las guías de configuración dejan para después: un backup que nunca se ha restaurado es una promesa, no una copia. La única forma de probar un backup de Supabase es restaurarlo, a propósito, en un sitio donde no importe, y mirar lo que vuelve. Un dump cortado a la mitad, un dump sin ninguna fila y un dump del proyecto equivocado están todos en el almacenamiento con el mismo aspecto que uno bueno.

Piensa en un simulacro de incendio. Un edificio lo hace una mañana cualquiera, cuando no arde nada, porque nadie debería bajar esas escaleras por primera vez el día en que se llenan de humo. Fuera, alguien pasa lista contra la lista de quién estaba dentro, y alguien apunta la fecha en la hoja junto a la puerta. Un simulacro de restauración es lo mismo: recorrer el camino, contar y apuntarlo.

¿Cómo sé si mi backup de Supabase funciona de verdad?

Restáuralo y mira. Es la única prueba que existe, porque nada en el propio archivo separa un backup bueno de uno roto.

El simulacro toma tu copia más reciente, la carga en un proyecto que no importa y le hace tres preguntas al resultado. ¿Está cada tabla, con más o menos tantas filas como la de producción? ¿La fila más reciente es de la noche en que se hizo la copia? ¿Puedes iniciar sesión como tú? Un archivo bueno responde que sí a las tres, y cada forma en que un backup sale mal falla al menos una de ellas.

Cinco formas en que un backup está mal y aun así parece bien

Las cinco terminan esa noche sin ningún error, y las cinco dejan un archivo con el nombre de siempre en el sitio de siempre. Solo se distinguen cuando se carga el archivo.

Qué le pasa al archivoCómo suele llegar a esoEl paso del simulacro que lo detecta
Se detiene a mitad de caminoUn script que pasa pg_dump a gzip informa de lo que hizo gzip. Un dump que murió a la mitad se guarda, y el job dice que salió bien. Un disco lleno o una subida que se rindió hacen lo mismoLa línea final, y luego los recuentos
Tiene tus tablas y ninguna de sus filassupabase db dump se ejecutó sin --data-only, que así solo escribe la estructuraLos recuentos: todas las tablas en cero
Tiene las filas y ninguna de las cuentasEl dump solo nombró tu propio esquema, y tus usuarios viven en uno llamado authLa búsqueda de auth.users, y luego el inicio de sesión
Son los datos de otro proyectoEl connection string apunta a una copia de staging o a un proyecto antiguoLa fila más reciente, del día equivocado
No se carga en absolutoUn dump de Postgres 17 cargado en Postgres 15, o líneas de propietario que el proyecto nuevo rechazaLa restauración se detiene con un error

La segunda y la tercera son el tema de por qué tu dump de Supabase no tiene usuarios, y las dos salen de un comando de dump ejecutado con menos opciones de las que necesitaba. La primera nos sorprendió, así que tiene una sección propia.

En el almacenamiento, los seis archivos parecen iguales. Al cargarlos, solo el primero te devuelve la base de datos que tenías.

¿Falla la restauración de un archivo de backup cortado?

No siempre. Cortamos uno a mitad de una tabla, lo cargamos con las opciones que usa la propia guía de Supabase, y psql terminó sin ningún error.

La prueba fue pequeña y fácil de repetir. El 27 de septiembre de 2026 hicimos un dump de una base de datos con dos tablas, una de 5.000 filas y otra de 300, cortamos el archivo en tres puntos distintos y cargamos cada versión con psql de Postgres 17.11. Cada carga usó --single-transaction y --variable ON_ERROR_STOP=1, las dos opciones que están ahí para detener una restauración ante el primer problema y deshacer todo lo hecho.

  • Cortado a mitad de un valor, psql se detuvo con un error y no escribió nada. Es el resultado que esperarías.
  • Cortado dentro de la última columna de una fila, terminó con código de salida 0, que es como un programa dice que salió bien. La primera tabla volvió con 2.596 de sus 5.000 filas, a la última le faltaba la mitad del texto, y la segunda tabla volvió vacía.
  • Cortado justo entre las dos tablas, también terminó con 0. La primera tabla estaba completa y la segunda vacía.

La razón está en cómo guarda las filas un dump. Las filas de cada tabla van en un bloque que termina con una línea que solo contiene \., y cuando el archivo se acaba antes de esa línea, psql toma el final del archivo como el final del bloque. La única señal de que faltaba algo es una línea que debería estar al final del todo.

Esa línea es la despedida de pg_dump. Un dump completo tiene las palabras PostgreSQL database dump complete cerca del final, y uno cortado no. De los tres archivos que escribe la CLI de Supabase, la línea solo sobrevive en data.sql, porque la CLI quita todos los comentarios del archivo de esquema (comprobado con la versión 2.111 de la CLI). Así que data.sql es el archivo donde buscar, y esa búsqueda es el segundo paso del simulacro.

La carga informó de éxito. La primera tabla volvió a medio llenar y la segunda volvió vacía.

¿Dónde debería restaurarlo?

En un proyecto de Supabase que no importe: un proyecto de prueba en tu cuenta, o un Supabase que corra en tu propio ordenador. Nunca en el proyecto que usa tu app.

Un proyecto de prueba en Supabase es lo más parecido a tu proyecto real, y es el destino para el que está escrita la guía de backup y restauración de Supabase: su primer paso es crear un proyecto nuevo. En el plan gratuito tienes derecho a dos proyectos gratuitos activos, y los pausados no cuentan, así que un proyecto de prueba normalmente no cuesta nada mientras tu base de datos quepa en el plan gratuito. En una organización de pago, el cómputo de un proyecto nuevo se cobra por horas, así que bórralo cuando termine el simulacro.

Supabase en tu propio ordenador no cuesta nada y no necesita cuenta. La CLI de Supabase ejecuta todo el stack en local con Docker: supabase init, luego supabase start, y muestra una dirección de base de datos en el puerto 54322 y una publishable key para el proyecto local. Antes de arrancarlo, abre supabase/config.toml y pon en major_version la versión mayor de Postgres de tu proyecto. El comentario encima de ese ajuste dice que tienen que coincidir, y la versión de tu proyecto está en Project Settings, luego General.

En Postgres 15 hay una trampa. Salvo que el job de backup fijara una versión, la CLI hizo la copia con pg_dump 17, y el archivo de datos lleva entonces, cerca del principio, SET transaction_timeout = 0, un ajuste que Postgres 15 no reconoce, así que la carga se detiene en esa línea. Para el simulacro, pon major_version en 17. Después aplica al job de backup el arreglo de una línea que explica el artículo sobre la GitHub Action, porque el proyecto en el que restaurarías de verdad sigue en 15.

Un Postgres pelado en Docker, sin nada de Supabase dentro, no basta. Un dump de Supabase hace referencia a cosas que solo crea Supabase, como el esquema auth donde viven tus usuarios y el rol authenticated que nombran tus reglas de seguridad, y la restauración se detiene en la primera línea que menciona una de ellas.

Una precaución, porque el proyecto de prueba ahora guarda una copia real. Tiene las direcciones de email de tus usuarios, así que no apuntes tu app ni sus webhooks a él, y bórralo cuando termines.

Las tareas programadas son lo que no viene. Si tu proyecto las ejecuta con la extensión pg_cron, los tres archivos de la CLI traen de vuelta la extensión y ninguna de sus tareas, porque las tareas son filas de cron.job y el dump de datos deja esas filas fuera. Lo comprobamos el 4 de octubre de 2026 con la versión 2.119 de la CLI, restaurando una base de datos que tenía una tarea programada. Por eso el proyecto de prueba se queda quieto, y una restauración de verdad a partir de estos archivos también arranca sin ninguna tarea programada, así que guarda tus llamadas a cron.schedule en algún sitio desde el que puedas volver a ejecutarlas.

Cómo probar un backup de Supabase, paso a paso

Seis pasos, y los tres primeros ocurren antes de restaurar nada.

  1. Busca la copia más reciente y lee su fecha. Si es más antigua que la última ejecución programada, el job se ha parado, y ese es tu primer hallazgo.
  2. Busca dump complete en data.sql. Una coincidencia significa que el archivo llegó hasta el final. Ninguna significa que se cortó, sea cual sea su tamaño. La búsqueda de un editor de texto sirve igual que una terminal:
    grep -c 'dump complete' data.sql
    
  3. Busca en él a tus usuarios. Una línea que empieza por COPY "auth"."users" con filas debajo significa que tus cuentas están en el archivo:
    grep -n 'COPY .*auth.*users' data.sql
    
  4. Cárgalo en el proyecto de prueba con el comando de la guía de Supabase, apuntado al connection string del proyecto de prueba. En un Supabase local ese string es postgresql://postgres:postgres@127.0.0.1:54322/postgres.
    psql \
      --single-transaction \
      --variable ON_ERROR_STOP=1 \
      --file roles.sql \
      --file schema.sql \
      --command 'SET session_replication_role = replica' \
      --file data.sql \
      --dbname "postgresql://…the spare's connection string…"
    
  5. Cuenta las filas y lee la más reciente, en las dos bases de datos. La consulta está en la sección siguiente.
  6. Inicia sesión en el proyecto de prueba como tú. El comando está en la sección de después.

Si el paso 4 se detiene con un error, el simulacro ya ha hecho su trabajo. Las notas de solución de problemas al final de la guía de Supabase cubren los dos errores más habituales, los dos sobre roles, y cómo restaurar un backup de Supabase explica de qué te protege cada opción de ese comando.

Faltan en esas notas otras dos paradas en roles.sql. Nos encontramos con las dos el 4 de octubre de 2026, al cargar los archivos de dos bases de datos Postgres 17, una de ellas un proyecto de Supabase, en una copia local nueva de Supabase: "supabase_admin" is a reserved role, only superusers can modify it, en una línea que empieza por ALTER ROLE "supabase_admin", y permission denied for parameter log_min_messages, en una línea que empieza por GRANT SET ON PARAMETER. Las dos líneas configuran roles que Supabase crea por su cuenta en cada proyecto, así que pon -- al principio de cada una para convertirla en un comentario y vuelve a ejecutar el comando. Nuestra Action de backup las comenta ya al hacer la copia.

Qué contar, y contra qué

Cuenta cada tabla en el proyecto de prueba y en tu proyecto en producción con la misma consulta, y pon las dos listas una al lado de la otra. La copia debería ir una noche por detrás de la base en producción: un poco más baja en una tabla que crece, y nunca en cero en una tabla que tenía filas.

Es pasar lista contra la lista de quién estaba dentro. Pega la consulta en el editor SQL de cada proyecto y pulsa Run. Cuenta las filas de cada tabla de tu propio esquema y de auth:

select table_schema, table_name,
       (xpath('/row/n/text()',
         query_to_xml(format('select count(*) as n from %I.%I', table_schema, table_name),
                      false, true, '')))[1]::text::bigint as row_count
  from information_schema.tables
 where table_schema in ('public', 'auth')
   and table_type = 'BASE TABLE'
 order by table_schema, table_name;

Lee cada fila de cada tabla, así que en una base de datos grande ejecútala fuera de tus horas de más actividad.

Luego lee la fila más reciente de una tabla que conozcas, solo en el proyecto de prueba. Sirve cualquier tabla con una columna created_at; pon su nombre en lugar de orders:

select max(created_at) from public.orders;

La respuesta debería estar cerca de la hora en que se hizo el backup. Una fecha semanas más antigua, o filas que no reconoces, significan que el archivo vino de otro proyecto.

ComprobaciónDóndeLo que muestra una copia buena
Filas en cada tablaEn los dosLas mismas tablas, cada una un poco por detrás de producción, ninguna vacía que tuviera filas
La fila más recienteProyecto de pruebaUna hora de la noche en que se hizo la copia
Tu propia cuentaProyecto de pruebaTu email en auth.users
Un inicio de sesiónProyecto de pruebaVuelve un token

Por qué el inicio de sesión es la prueba que demuestra tus cuentas

Un recuento de auth.users demuestra que las filas llegaron. Un inicio de sesión demuestra que funcionan: que la contraseña guardada, el servicio de inicio de sesión del proyecto de prueba y tu dirección de email siguen de acuerdo entre sí.

Usa tu propia cuenta, con una contraseña que conozcas. La dirección del proyecto y la publishable key del proyecto de prueba están en su panel Connect, o en la salida de supabase start en un Supabase local:

curl -X POST 'https://…the spare's project ref….supabase.co/auth/v1/token?grant_type=password' \
  -H "apikey: sb_publishable_…" \
  -H "Content-Type: application/json" \
  -d '{"email": "you@example.com", "password": "…"}'

Es la llamada de inicio de sesión de la propia documentación de Supabase, dirigida al proyecto de prueba. Una respuesta que contiene access_token significa que tu cuenta llegó con una contraseña que funciona. Invalid login credentials, para una cuenta que inicia sesión sin problemas en tu app en producción, significa que no llegó, y por qué un dump llega sin las cuentas es el artículo para ese resultado.

Si todo el mundo inicia sesión en tu app con Google, esta llamada no tiene nada que probar, porque el proyecto de prueba no tiene configurado el inicio de sesión con Google. Busca en su lugar tu propio email en auth.users después de restaurar. Eso muestra que la fila de la cuenta llegó, aunque no que su contraseña funcione.

Archivos: la mitad que una restauración de la base no puede probar

La copia de la base de datos guarda una fila por cada archivo subido y ninguno de los archivos. Si copias tus buckets de Storage con un job propio, que es la única forma de que se copien, hazle un simulacro a esa copia también.

Toma las tres filas más recientes de la base restaurada:

select bucket_id, name from storage.objects order by created_at desc limit 3;

Busca esas tres rutas en tu copia de los archivos y abre cada una. Una ruta sin archivo detrás es una imagen que tus usuarios verían rota después de una restauración real.

¿Puedo probar los backups que Supabase hace por mí?

En un plan de pago, sí, con Restore to a New Project. Es la única forma de abrir una de las copias diarias de Supabase, porque en los proyectos actuales no puedes descargarlas.

Supabase describe la función como una forma de hacer pruebas sin riesgo. Elige una copia en la pestaña Restore to a New Project de la página Backups, y Supabase crea con ella un proyecto nuevo con tus usuarios y sus contraseñas hasheadas, listo para los mismos recuentos y el mismo inicio de sesión. Dos cosas que conviene saber antes de pulsar. El proyecto nuevo se factura como un proyecto aparte, y Supabase te muestra el coste antes de empezar. Y lo copia todo, tareas programadas incluidas: Supabase dice que las tareas de pg_cron, pg_net y los wrappers empiezan a ejecutarse en cuanto termina la restauración, sin forma de pausarlas antes. Si una tarea de tu app envía emails o cobra una tarjeta, el proyecto de prueba también lo hará.

Si además guardas un archivo fuera de la cuenta, ese archivo necesita su propio simulacro.

¿Cada cuánto debería probar una restauración?

Una vez ahora, luego cada tres meses, y otra vez siempre que cambie algo en cómo se hace el backup.

Los cambios que importan son los que rompen un backup en silencio: un workflow nuevo o editado, una contraseña de base de datos restablecida, un cambio a un plan nuevo o a una versión nueva de Postgres, una tabla nueva en la que tu app ha empezado a escribir. Después de cada uno, el simulacro del trimestre pasado ya no describe el archivo de este trimestre.

Luego apúntalo, que es la hoja junto a la puerta. Una línea por simulacro, en un sitio al que llegues sin lo que se ha roto: la fecha, qué archivo, los recuentos que importaban, si el inicio de sesión funcionó y cuánto tardó el simulacro entero. Vale un archivo de texto en el repositorio del backup, y también un evento recurrente en el calendario con los resultados pegados. La fecha responde a «cuándo lo comprobamos por última vez» en la hora en que alguien necesita saberlo, y lo que tardó es tu primera estimación de cuánto tiempo una restauración real dejaría tu app parada.

Dónde encaja Reeve Care

Care guarda copias de tu base de datos de Supabase fuera de tu cuenta de Supabase, según el horario de tu plan, comprueba cada copia en el momento de hacerla y la devuelve a su sitio con un botón.

  • Las copias siguen el horario de tu plan, desde una vez al día hasta cada seis horas.
  • Una copia cortada se detecta en el momento de hacerla. La línea final de pg_dump tiene que estar en el archivo, o la copia no pasa la comprobación y nunca se convierte en la fecha de tu panel.
  • Cada tabla se cuenta mientras se escribe la copia. Cuando una tabla que tenía filas en la copia anterior no tiene ninguna en esta, una persona de Reeve se entera.
  • Tus cuentas van dentro, y tus archivos subidos también vienen en cuanto conectas una credencial de Storage.
  • Restaurar es un botón, y antes de reemplazar nada se hace una copia del estado actual.
  • Cualquier copia se descarga como zip con schema.sql, data.sql, roles.sql y un manifiesto con el número de filas de cada tabla, que es la mitad «contra qué» de este artículo, ya apuntada.

Un simulacro trimestral demuestra la copia que elegiste ese día, y la comprobación se hace en cada copia en el momento de hacerla. La copia, la comprobación y la restauración están dibujadas paso a paso en la página de backups de Supabase, y qué incluye cada plan, horario incluido, está en la página de precios.

Qué hacer esta semana

Qué hacer

  • Busca tu backup más reciente y lee su fecha. Si es más antiguo que la última ejecución programada, arregla el job antes que nada.
  • Busca dump complete y COPY "auth"."users" en data.sql. Dos búsquedas te dicen si el archivo llega al final y si tus cuentas están dentro.
  • Crea un proyecto de prueba, o arranca Supabase en tu propio ordenador, y carga el archivo con el comando psql de la guía de Supabase.
  • Ejecuta la consulta de recuento en las dos bases de datos y pon las dos listas una al lado de la otra. Lee la fila más reciente de una tabla que conozcas.
  • Inicia sesión en el proyecto de prueba como tú.
  • Apunta la fecha, los recuentos y cuánto tardó, y luego borra el proyecto de prueba.

Antes de cerrar esta pestaña, busca dump complete en tu data.sql más reciente. Es una sola búsqueda, y te dice si el archivo al que llamas backup llega a su propia última línea. Si todavía no tienes un archivo en el que buscar, una GitHub Action gratuita es la forma más rápida de empezar a generarlos.

Preguntas frecuentes

¿Cómo sé si mi backup de Supabase funciona de verdad?

Restáuralo en un proyecto que no importe y mira lo que vuelve. Compara el número de filas de cada tabla con la base de datos en producción, comprueba que la fila más reciente es de la noche en que se hizo la copia e inicia sesión como tú. Nada en el propio archivo distingue un dump bueno de uno roto: su nombre, su tamaño y la marca verde junto al job son iguales en los dos casos.

¿Cada cuánto debería probar una restauración?

Una vez ahora, luego cada tres meses, y otra vez siempre que cambie la forma en que se hace el backup: un workflow nuevo o editado, una contraseña de base de datos restablecida, un plan o una versión de Postgres nuevos, o una tabla nueva en la que escribe tu app. Apunta la fecha cada vez, con los recuentos y cuánto tardó, para que la pregunta de cuándo se comprobó por última vez tenga respuesta.

¿Puedo probar una restauración sin tocar mi base de datos en producción?

Sí, y siempre deberías hacerlo así. Restaura en un proyecto de prueba de Supabase, algo que el plan gratuito permite, o en un Supabase que corre en tu propio ordenador con la CLI y Docker. Lo único que el simulacro le hace a la base en producción es leerla una vez para contar sus filas. Borra el proyecto de prueba después, porque guarda una copia real de tus usuarios.

¿Qué debería comprobar después de restaurar un backup?

Cuatro cosas. El número de filas de cada tabla junto al de producción, donde la copia debería ir un poco por detrás y nunca en cero para una tabla que tenía filas. La fila más reciente de una tabla que conozcas, que debería ser de la noche de la copia. Tu propio email en auth.users. Y un inicio de sesión como tú, la única comprobación que demuestra que las cuentas funcionan y no solo que llegaron.

La restauración funcionó, pero nadie puede iniciar sesión. ¿Por qué?

Casi siempre porque el archivo nunca tuvo tus cuentas. Supabase las guarda en un esquema llamado auth, y un dump que solo nombró tu propio esquema, o un supabase db dump sin opciones, las deja fuera mientras cada una de tus tablas se restaura sin problema. Busca primero COPY "auth"."users" en el archivo. Si no está, haz un dump de datos con --data-only, que recorre el esquema auth y se lleva a tus usuarios.

¿Falla la restauración de un archivo de backup cortado?

No siempre. Cortamos un archivo de pg_dump en tres puntos y cargamos cada versión con --single-transaction y ON_ERROR_STOP, las opciones de la guía de restauración de Supabase. Un corte a mitad de un valor se detuvo con un error. Un corte dentro de la última columna de una fila y un corte entre dos tablas terminaron los dos sin error, con las tablas incompletas. Un dump completo lleva la línea PostgreSQL database dump complete cerca del final, así que búscala antes de fiarte de un archivo.

Escrito por

Vlad Tkachenko

Fundador de Reeve

Me paso el día mirando apps creadas con Lovable, Bolt, v0, Cursor y Replit, y la corta lista de errores que aparecen en ellas una y otra vez.

Más sobre el autor

Sigue leyendo

Todos los artículos

¿No sabes cómo está tu propia app?

Haz un escaneo gratuito y obtén una nota clara de la A a la F en unos 20 segundos. Sin cuenta y sin tarjeta.

Analizar mi app gratis

Comprobación externa automatizada, no una auditoría completa. La ausencia de hallazgos no es garantía de seguridad.