Architecture & Delivery
SupabaseJWTAuthenticationProduct ArchitectureRisk Patterns

Cómo un JSON enorme en user_metadata de Supabase puede romper tu aplicación

Los productos rara vez caen por una única decisión catastrófica. Caen por una cadena de atajos «inofensivos» que crece en silencio hasta que todo salta.

`user_metadata` de Supabase es una trampa así: útil al principio, peligrosa al escalar y demasiado fácil de usar mal.

Se trata como un cajón para datos del usuario. Solo es JSON, ¿no? Sí, con una consecuencia: Supabase incluye metadata en el JWT de sesión. En el escenario con cookies que describo, ese token viaja con las peticiones. Más metadata, peticiones mayores.

No es un patrón de almacenamiento. Es un patrón de carga transportada. Tiene consecuencias de arquitectura.

Meme about guys sitting still and then cheering

El mecanismo oculto

El camino:

1. Guardas datos en `auth.users.user_metadata`.

2. Supabase refleja metadata en el JWT.

3. El JWT se guarda en cookies.

4. Las cookies viajan con las peticiones.

5. Toda la cadena transporta datos personales que no necesitaba.

Funciona hasta que deja de funcionar.

Unos pocos campos parecen inocentes. Añade comportamiento, estado de UI, preferencias de directorios y análisis del perfil. Crecen peticiones y cabeceras, depurar se vuelve incoherente y la autenticación parece un semáforo en cortocircuito.

Acaba rompiéndose algo. Síntomas:

•La aplicación cierra sesiones sin avisar.
•El navegador rechaza peticiones.
•El servidor devuelve HTTP 431: Request Header Fields Too Large.

Da igual lo limpio que sea tu código. La autenticación es el cuello de botella.

Cuando me pasó

No hablo de teoría. Me di contra esa pared.

Pasé dos fines de semana enteros investigando una autenticación de pronto inestable. Sin grandes despliegues ni funciones complejas. Solo añadidos pequeños a `user_metadata`: una línea aquí, un estado de UI allá.

Nada que pareciera peligroso. Todo lo que sí lo era.

No era la base. Ni la infraestructura. Ni el rendimiento en el sentido habitual. Era el JWT.

El token debía ser una llave y se había convertido en una maleta de JSON arrastrada en cada petición. No por megabytes, sino por unas decenas de líneas de metadata acumuladas más allá de lo razonable.

No una brecha espectacular. Una asfixia lenta.

El principio que nadie enseña

Sesión ≠ almacén

Tu JWT no es un almacén, una caché ni un contenedor del contexto cambiante del producto.

Debe ser pequeño, previsible, estable y aburrido. Lo demás tiene otro sitio.

¿Saber quién es el usuario? Bien. ¿Sus preferencias, analítica, estado de UI, acciones recientes y media hoja de ruta? Estás metiendo el producto en el pasaporte. Y los pasaportes no sirven para transportar muebles.

El patrón correcto

Usa `user_metadata` para lo que cabe en una tarjeta de visita. El resto, a tablas dedicadas.

Mi regla: contexto de identidad en `user_metadata`; lo demás, tablas propias. ¿Cambia con el tiempo? No lo metas en la sesión. ¿Parece cómodo? Cuestiónalo. ¿Dudas? Sepáralo.

La visión completa

No va solo de Supabase, sino de productos que escalan frente a productos que acumulan entropía.

Los pequeños errores aparecen cuando el producto empieza a ganar tracción: el peor momento para una sorpresa.

¿La sesión pesa demasiado? ¿Los registros de acceso son acertijos? ¿Metadata hace más trabajo que la base? Estás al principio de un fallo evitable. Lo bueno: se puede arreglar.

Conclusión

Los productos que funcionan no se ahogan en sus datos. Los estructuran.

Autenticar debería ser un apretón de manos, no un servicio de carga. Si el JWT lleva metadata en lugar de identidad, no escalas: te atascas. Y puedes corregirlo antes de que salga caro.

Hablemos de claridad.

Menos charla — más beneficio. Construyamos un sistema real!

Ingeniería directa a nivel de código para operaciones que no pueden permitirse fallos ni retrasos de agencia