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.

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 archivo | Cómo suele llegar a eso | El paso del simulacro que lo detecta |
|---|---|---|
| Se detiene a mitad de camino | Un 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 mismo | La línea final, y luego los recuentos |
| Tiene tus tablas y ninguna de sus filas | supabase db dump se ejecutó sin --data-only, que así solo escribe la estructura | Los recuentos: todas las tablas en cero |
| Tiene las filas y ninguna de las cuentas | El dump solo nombró tu propio esquema, y tus usuarios viven en uno llamado auth | La búsqueda de auth.users, y luego el inicio de sesión |
| Son los datos de otro proyecto | El connection string apunta a una copia de staging o a un proyecto antiguo | La fila más reciente, del día equivocado |
| No se carga en absoluto | Un dump de Postgres 17 cargado en Postgres 15, o líneas de propietario que el proyecto nuevo rechaza | La 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.
¿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,
psqlse 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.
¿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.
- 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.
- Busca
dump completeendata.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 - 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 - 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…" - Cuenta las filas y lee la más reciente, en las dos bases de datos. La consulta está en la sección siguiente.
- 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ón | Dónde | Lo que muestra una copia buena |
|---|---|---|
| Filas en cada tabla | En los dos | Las mismas tablas, cada una un poco por detrás de producción, ninguna vacía que tuviera filas |
| La fila más reciente | Proyecto de prueba | Una hora de la noche en que se hizo la copia |
| Tu propia cuenta | Proyecto de prueba | Tu email en auth.users |
| Un inicio de sesión | Proyecto de prueba | Vuelve 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_dumptiene 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.sqly 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 completeyCOPY "auth"."users"endata.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
psqlde 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.