Як великий JSON у Supabase user_metadata може зламати застосунок
Сучасні продукти рідко гинуть від одного катастрофічного рішення. Частіше — від ланцюга «нешкідливих» скорочень, які тихо ростуть, доки все не трісне.
`user_metadata` у Supabase — приклад такої пастки: корисний на старті, небезпечний у масштабі й дуже зручний для неправильного використання.
Команди часто сприймають його як випадкове місце для даних користувача. Це ж просто JSON? Так, але з наслідком: Supabase включає metadata у JWT сесії. У описаному cookie-сценарії цей токен живе в cookies й подорожує з запитами. Більше metadata — більші запити.
Це не патерн зберігання. Це патерн навантаження. І він має архітектурні наслідки.

Прихований механізм
Шлях виглядає так:
1. Зберігаєте дані в `auth.users.user_metadata`.
2. Supabase відображає metadata у JWT.
3. JWT зберігається в cookies.
4. Cookies їдуть із запитами.
5. Увесь delivery-конвеєр перевозить персональні дані, яких йому не треба.
Працює, доки не перестає.
Кілька полів здаються невинними. Додайте поведінку, стан UI, налаштування каталогів, аналіз профілю — і запити ростуть, заголовки пухнуть, дебаг стає непослідовним, а автентифікація — світлофором із коротким замиканням.
Зрештою щось голосно ламається. Типові симптоми:
Тут уже неважливо, який чистий код. Шар автентифікації став вузьким місцем.
Коли це стало реальним
Я не теоретизую. Сам урізався в цю стіну.
Два повні вихідні з’ясовував, чому вхід раптом ненадійний. Без великих деплоїв і складних релізів. Лише дрібні доповнення в `user_metadata`: рядок тут, стан інтерфейсу там.
Нічого, що виглядало небезпечним. Усе, що ним було.
Не база. Не інфраструктура. Навіть не продуктивність у звичному сенсі. JWT.
Токен мав бути ключем, а став валізою з JSON, яку тягали з кожним запитом. І причина не в мегабайтах, а в кількох десятках рядків metadata, що непомітно перейшли межу здорового глузду.
Не драматичний злам. Повільне удушення.
Принцип, якого не вчать
Сесія ≠ сховище
JWT — не склад, не кеш і не контейнер для мінливого контексту продукту.
Токен сесії має бути малим, передбачуваним, стабільним і нудним. Для решти є інші місця.
Знати, хто користувач, — нормально. Носити його вподобання, аналітику, UI, останні дії й половину roadmap — це пакувати продукт у паспорт. А паспорт не для перевезення меблів.
Правильний патерн
У `user_metadata` залишайте те, що вміститься на візитівці. Решту — в окремі таблиці.
Моє правило: контекст ідентичності — `user_metadata`, решта — власні таблиці. Змінюється з часом — не кладіть у сесію. Здається зручним — перепитайте себе. Не впевнені — ізолюйте.
Ширший погляд
Це не стільки про Supabase, скільки про різницю між продуктом, який масштабується, і продуктом, який накопичує ентропію.
Малі помилки проявляються не одразу. Вони виходять саме тоді, коли продукт набирає попит — у найгірший момент для сюрпризів.
Сесія вже важча, ніж мала б? Логи входу — загадки? Metadata працює більше за базу? Ви на початку відмови, якої можна уникнути. Хороша новина: це виправляється.
Висновок
Успішні продукти не тонуть у власних даних. Вони їх структурують.
Автентифікація — рукостискання, не вантажна доставка. Якщо JWT несе metadata замість ідентичності, ви не масштабуєтеся — буксуєте. І це можна виправити до того, як стане дорого.
Поговорімо про ясність.


