Saltar al contenido

Backups

Por qué tu dump de Supabase no tiene usuarios dentro

Ejecuta supabase db dump por sí solo y obtienes la forma de tu base de datos y ninguna de sus filas, sin el esquema auth donde viven tus usuarios.

Vlad Tkachenko11 min de lectura
Un archivo sellado con tres filas de datos, y a su lado un registro rayado de personas que queda fuera y lo corta el borde del marco.

En resumen

  • Supabase publica su backup como tres comandos. El que probablemente ejecutaste es el segundo, y tus usuarios están en el tercero.
  • Ejecuta supabase db dump sin más flags y obtienes la forma de tus tablas y nada de su contenido, y el esquema auth donde viven tus usuarios queda fuera hasta de eso.
  • Una sola búsqueda en el archivo que ya tienes te dice cuál de tres cosas estás sosteniendo.

Hiciste lo sensato. Buscaste cómo hacer copia de una base de datos de Supabase, ejecutaste el comando que encontraste y guardaste el archivo en un sitio seguro.

Entonces un día lo necesitas. Vuelcas el archivo en un proyecto nuevo y la restauración termina sin un solo error. Cada tabla que llegaste a crear está ahí, y cada una de ellas está vacía. Tus usuarios están peor todavía: la parte de la base de datos donde viven, un esquema llamado auth, nunca llegó al archivo.

Aquí está la parte que casi todas las guías se saltan: supabase db dump por sí solo no es una copia de tus datos. Sin más flags escribe la forma de tu base de datos y nada de su contenido, y a auth lo deja fuera hasta de eso. Supabase publica el backup como tres comandos, y tus cuentas viajan en el tercero.

Ayuda pensar en un hotel. Tus tablas son las habitaciones y todo lo que hay en ellas. El registro de la recepción, el que tiene el nombre de cada huésped, es del hotel. Y un plano te enseña cada habitación del edificio sin poner un solo huésped dentro.

¿Un backup de Supabase incluye mis usuarios?

Depende de qué comando escribió el archivo, y el comando que ejecuta la mayoría no los incluye.

Tus usuarios no son filas de ninguna de tus tablas. Supabase los guarda en un cajón aparte de la misma base de datos, el esquema auth, junto con sus contraseñas hasheadas, los proveedores con los que entraron y las sesiones que tienen abiertas. Tus propias tablas están en un cajón llamado public, y cada columna user_id que hay en ellas es una referencia hacia auth.

Un esquema es exactamente eso: un cajón con nombre dentro de una base de datos. public es tuyo. auth es de Supabase, y storage también, que guarda la fila que describe cada archivo subido. La documentación de Supabase llama a estos sus esquemas gestionados y dice que normalmente no hace falta traerlos salvo que los hayas modificado, que es la razón por la que las herramientas los tratan distinto de tus tablas.

Esa división es lo que permite que un comando produzca dos archivos que se parecen y contienen cosas completamente distintas.

Ejecutado por sí solo, el comando de dump copia la forma de tu propio cajón y se detiene en la frontera de los dos que lleva Supabase.

Qué escribe el comando de dump por sí solo

El plano. Ninguna fila, y nada de auth.

La página de referencia de Supabase para el comando lo dice en dos frases. Ejecuta pg_dump con flags adicionales para excluir los esquemas gestionados por Supabase, y entre los ignorados están auth, storage y los creados por extensiones. La misma página dice después que el dump por defecto no contiene datos ni roles propios, y que los consigues pidiéndolos con --data-only y --role-only.

Así que esto, que es lo que probablemente ejecutaste:

supabase db dump --db-url "postgresql://…your connection string…" -f backup.sql

produce un archivo lleno de sentencias CREATE TABLE. Cada columna, cada índice, cada política que escribiste sobre tus propias tablas, y ni una sola fila de nada.

La razón por la que esto es peor que un archivo obviamente vacío es que funciona. Tampoco se ve pequeño: cada definición de tabla, cada índice y cada política que llegaste a escribir están ahí, y para una app de verdad eso es mucho texto. Un backup vacío se anuncia solo. Este se restaura limpio, y lo primero que te dice otra cosa es una pantalla de acceso que ninguna cuenta consigue pasar.

El mismo comando escribe los dos. Cuál tienes en la mano depende de un flag, y los dos se restauran sin un error.

¿Cómo compruebo el dump que ya tengo?

Ábrelo en un editor de texto y busca auth. Lo que salga coloca tu archivo en uno de tres grupos.

  1. Ninguna coincidencia. El esquema auth no está en este archivo de ninguna forma. Esto es lo que escribe un supabase db dump a secas.
  2. Coincidencias, pero solo en líneas que empiezan por CREATE, ALTER o GRANT. Tienes el diseño del registro y a nadie dentro.
  3. Una línea que dice COPY "auth"."users" o COPY auth.users, con filas de datos debajo hasta una línea con \. O una serie de líneas que empiezan por INSERT INTO "auth"."users". Tus cuentas están ahí.

Si prefieres hacerlo en la línea de comandos, dos greps responden lo mismo:

grep -c 'auth.*users' backup.sql
grep -n 'COPY .*auth.*users\|INSERT INTO .*auth.*users' backup.sql

El primero dice si el esquema llegó al archivo. El segundo dice si llegaron las personas. Un cero de los dos, en un archivo con el que contabas, es mejor descubrirlo hoy que la mañana en que lo necesitas.

Busca storage ya que estás, y lee con cuidado lo que encuentres. Esas filas son la lista de tus archivos subidos, que es una cosa distinta de los archivos, y ningún backup de base de datos en ningún plan contiene esos.

¿Cómo exporto los usuarios auth de Supabase?

Con el comando de datos, que es un comando distinto del que escribe el esquema.

La guía de backup y restauración de Supabase publica el backup como tres archivos, y vale la pena verlos juntos porque la forma es la respuesta:

supabase db dump --db-url "postgresql://…" -f roles.sql --role-only
supabase db dump --db-url "postgresql://…" -f schema.sql
supabase db dump --db-url "postgresql://…" -f data.sql --use-copy --data-only \
  -x "storage.buckets_vectors" -x "storage.vector_indexes"

La segunda línea es la que se ejecuta suelta. La tercera es la que lleva tus usuarios.

Esos dos hechos parecen una contradicción y no lo son. La frase de la página de referencia de Supabase sobre excluir auth describe el dump de esquema, y el dump de datos sí recorre ese esquema.

Si solo quieres las cuentas, nombra el esquema y obtienes ese cajón solo:

supabase db dump --db-url "postgresql://…" -f users.sql --data-only --use-copy --schema auth

Antes de confiar en cualquiera de estos, añade --dry-run y lee lo que sale. Imprime el comando pg_dump que la herramienta va a ejecutar sin ejecutarlo, así ves por ti mismo qué esquemas se incluyen y cuáles se excluyen en la versión que tienes instalada. Lee esa salida una vez y no tendrás que creerle nunca a este artículo, ni a ningún otro, lo cual importa porque los flags sí se mueven entre versiones y el archivo se ve igual de todos modos.

También está la vía directa, y para eso está un pg_dump a secas: nombra los cajones que quieres y se los lleva.

pg_dump "postgresql://…" --schema public --schema auth --schema storage \
  --no-owner --file backup.sql

Una cosa más sobre el archivo de esquema, porque explica por qué esto está separado. Un proyecto nuevo de Supabase llega con un esquema auth ya construido, en la versión que el servicio de inicio de sesión corre hoy. Volcar encima la versión de tu proyecto viejo pondría un diseño más antiguo sobre uno que funciona. Lo que quieres llevarte es el contenido del registro, y eso es lo que guarda el archivo de datos.

Qué se rompe al devolver los usuarios

Dos cosas, y Supabase documenta las dos.

Los triggers, que pueden cifrar una columna dos veces. El comando de restauración de la guía de Supabase tiene en medio una instrucción fácil de leer como relleno:

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://…"

Esa línea del medio apaga los triggers mientras dura, y la guía dice que está para evitar que las columnas se cifren una segunda vez al entrar. Vuelca un archivo de datos sin ella y las contraseñas llegan ya revueltas por un proceso que ya se les había aplicado, y nada posterior lo deshace.

La propiedad y los permisos, que detienen el volcado. Un dump sacado de un proyecto de Supabase lleva líneas que se refieren a roles que el proyecto nuevo no te deja tocar. Las notas de resolución de problemas de esa misma guía dicen que comentes cualquier línea con ALTER ... OWNER TO "supabase_admin" en schema.sql, y una línea concreta GRANT "postgres" TO "cli_login_postgres" en roles.sql. Las dos son una edición de texto antes de empezar, y las dos detienen el volcado con la línea en la que se atragantó impresa en tu pantalla.

¿Mis usuarios tienen que entrar otra vez?

Sus contraseñas pasan. Sus sesiones no, salvo que te lleves una cosa más con ellas.

Supabase dice que puedes migrar cada tabla del esquema auth, usuarios y sus contraseñas hasheadas incluidos, así que nadie tiene que restablecer una contraseña que ya tenía. En ningún punto de esto se lee una contraseña; lo que se mueve es su hash.

Una sesión es otra cosa. Se prueba con un token que se firmó con el secreto JWT propio de tu proyecto, y cada proyecto tiene el suyo. Supabase dice que si el proyecto nuevo firma con otro secreto, cada token que ya está en el navegador de alguien queda inválido y a esa persona se le pide entrar de nuevo. Puedes evitarlo poniendo el secreto del proyecto viejo en el nuevo, y en esa misma página está el precio: cambiar el secreto JWT regenera las claves anon y service_role de ese proyecto, así que hay que darle a tu app las nuevas antes de que pueda hablar con nada. Cuál clave es cuál, y cuál de ellas puede estar en tu app siquiera, es lo que conviene tener claro antes de pegar ninguna.

Así que la versión honesta es que una restauración suele pedirle a todo el mundo que entre una vez. Eso es un correo de soporte. No es una cuenta perdida, y la diferencia entre las dos cosas es si el esquema auth estaba en tu archivo.

Tres cosas siguen sin estar ahí, hagas lo que hagas con los flags. Tus archivos subidos, porque Storage guarda los bytes fuera de la base de datos y ningún dump en ningún plan los alcanza. Tus edge functions, que son una descarga aparte y cuyos import maps, señala Supabase, no se traen automáticamente. Y los ajustes de tu proyecto, que son configuración y no datos y se vuelven a escribir a mano.

Qué hacer esta semana

Qué hacer

  • Coge el archivo de backup más reciente que tengas y búscale auth. Grupo uno, dos o tres de la sección de arriba, y lo sabrás en un minuto.
  • Si es grupo uno o dos, saca hoy un dump de datos con --data-only y --use-copy, y guárdalo junto al archivo de esquema en vez de en su lugar. Necesitas los dos.
  • Añade --dry-run al comando que acabes usando y lee la salida una vez, para saber qué cajones se lleva tu versión de la herramienta.
  • Apunta el orden de la restauración donde lo vayas a encontrar: roles, luego schema, luego SET session_replication_role = replica, luego data.
  • Restaura una vez en un proyecto desechable y luego intenta entrar como un usuario real. Es la única comprobación que prueba aquello de lo que trata este artículo.

Hacer esto una vez a mano vale la pena acabes como acabes haciendo tus copias, porque hasta que no abres un dump solo has tenido la palabra backup. Si sigues haciéndolo a mano es otra pregunta, y las tres vías y lo que cuesta cada una es donde se responde.

Dónde encaja Reeve Care

Care saca la copia según un calendario, y el registro va dentro.

La copia guarda tus tablas y tus cuentas. El botón de restaurar devuelve tus tablas y deja las cuentas donde están.
  • Tus cuentas están en la copia. El esquema auth viaja con tus propias tablas, porque una copia de una app de Supabase sin sus usuarios es una copia de la mitad. Las filas de storage que describen tus archivos vienen también, y los archivos mismos en cuanto conectas una credencial de Storage.
  • El botón de restaurar devuelve tus tablas y deja las cuentas en paz. Volcar auth.users sobre un proyecto vivo cierra la sesión de todos y devuelve cuentas que alguien borró a propósito, así que eso sigue siendo una petición con una persona detrás. Y así pulsar el botón en pleno susto no puede echar fuera a los clientes a los que querías ayudar.
  • La copia se relee antes de contar como sacada. La fecha de tu panel es la última vez que se abrió y se verificó una copia, nunca el momento en que arrancó un trabajo o aterrizó un archivo.
  • Restaurar toma antes una instantánea del estado actual, así que la propia restauración tiene un deshacer.

Care empieza en $49 al mes por una app. Es un precio de lista, y la página de precios a veces está por debajo de la cifra de aquí y nunca por encima.

Cómo se saca, se comprueba y se devuelve una copia está dibujado paso a paso en la página de backups de Supabase.

Antes de cerrar esta pestaña, abre tu dump más reciente y búscale auth. Es la forma más rápida de averiguar si eso que venías llamando backup te devolvería a tus clientes, y si la respuesta resulta ser que no, restaurar uno como toca es lo siguiente que leer.

Preguntas frecuentes

¿Un backup de Supabase incluye mis usuarios?

Depende de qué comando escribió el archivo. Tus usuarios viven en un esquema llamado auth, que pertenece al servicio de inicio de sesión. Un supabase db dump a secas deja auth fuera y no contiene ninguna fila de nada, porque el dump por defecto es solo el esquema. La mitad de datos del dump, que es un segundo comando con el flag --data-only, es la que lleva tus usuarios. Supabase publica el backup como tres comandos exactamente por eso.

¿Por qué falta auth.users en mi dump?

Porque casi seguro ejecutaste el dump de esquema. Supabase documenta que el comando excluye sus esquemas gestionados, que entre los ignorados están auth y storage, y que el dump por defecto no contiene datos en absoluto. Es deliberado: un proyecto nuevo llega con su propio esquema auth ya construido por el servicio de inicio de sesión, así que volcar encima una copia más vieja reemplazaría algo que funciona. Lo que quieres mover es el contenido, y eso lo lleva el dump de datos.

¿Cómo exporto los usuarios auth de Supabase?

Con el comando de datos, que está separado del comando de esquema. Ejecuta supabase db dump con --data-only y --use-copy para escribir un archivo de datos, y las tablas de auth vienen con él. Si solo quieres las cuentas, añade --schema auth y obtienes un archivo con ese esquema y nada más. Antes de confiar en cualquiera de los dos, añade --dry-run: imprime el comando pg_dump que la CLI va a ejecutar sin ejecutarlo, así lees qué esquemas se incluyen en la versión que tienes.

¿Las contraseñas sobreviven a una restauración de Supabase?

Sí, si el esquema auth estaba en el archivo. Supabase dice que puedes migrar cada tabla del esquema auth, contraseñas hasheadas incluidas, así que nadie tiene que restablecerlas ni crearlas de nuevo. Lo único que puede arruinarlas es volcar los datos sin desactivar antes los triggers, que es la razón por la que Supabase pone SET session_replication_role = replica en medio de su propio comando de restauración. Sáltate esa línea y una columna ya cifrada se cifra una segunda vez al entrar.

¿Mis usuarios seguirán con la sesión abierta tras una restauración?

No, si el proyecto nuevo firma con otro secreto. Una sesión se prueba con un token firmado con el secreto JWT del proyecto, y Supabase dice que un secreto nuevo invalida los tokens existentes, así que a todos se les pide entrar otra vez. Puedes llevarte el secreto viejo y mantenerlos dentro, pero Supabase también dice que cambiar el secreto JWT regenera las claves anon y service_role de ese proyecto, así que tu app necesita las nuevas.

¿Qué más deja fuera un dump de Supabase?

Tus archivos subidos, lo primero. Storage guarda una fila en tu base de datos por cada archivo y el archivo en otro sitio, así que ningún dump de base de datos en ningún plan contiene los bytes. Las edge functions son una descarga aparte, y Supabase señala que los import maps y los archivos deno.json no se traen automáticamente. Los ajustes del proyecto, los proveedores de auth y los secretos son configuración y no datos, y viven en el dashboard, así que se vuelven a escribir a mano en un proyecto nuevo.

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.