TL;DR
- Supabase free plan: 5GB egress/month
- My project: 10.26GB (205% over limit)
- Root cause: 5-second polling ×
select('*')on a table with a 200,000-char text column - Fix: generated column flag + select column restriction + visibilitychange polling stop
What happened
My KOBO project (issue-finder) had a collection-queue-form component polling if_jobs every 5 seconds via select('*'). The table includes raw_input_text (up to 200K chars). Through Vercel Functions, every poll was shipping that full column downstream.
5s interval × 200,000 chars × hours of operation = GB gone
Noticed when I checked the Supabase dashboard on 2026-05-31.
Fix 1: Generated column as boolean flag
If I only need to know whether raw input exists, I don't need to ship the text:
ALTER TABLE if_jobs
ADD COLUMN has_raw_input boolean
GENERATED ALWAYS AS (raw_input_text IS NOT NULL) STORED;
Fix 2: Narrow the select
// Before
const { data } = await supabase.from('if_jobs').select('*')
// After — list view only needs lightweight columns
const { data } = await supabase
.from('if_jobs')
.select('id, status, has_raw_input, created_at, updated_at')
Fix 3: Slow down polling + stop on hidden tab
useEffect(() => {
let interval: ReturnType<typeof setInterval> | null = null
const start = () => { interval = setInterval(fetch, 30_000) } // 5s → 30s
const stop = () => { if (interval) clearInterval(interval) }
document.addEventListener('visibilitychange', () =>
document.hidden ? stop() : start()
)
start()
return stop
}, [])
When does this happen to you?
-
select('*')on a table with large text/JSON columns - Polling interval ≤ 10s
- Serverless function proxy (Vercel, etc.) — egress counted on every hop
Full writeup (Japanese): https://masatoman.net/articles/supabase-egress-overage-free-plan-2026
Top comments (0)