30 October 2026 · 9 min read · BlitzHash Team · Supabase

Supabase egress cost explained: what's using your bandwidth and how to cut it

Supabase egress cost is the charge for data leaving your project: every row, file, login response and realtime message that travels from Supabase to a browser, phone or server. If your egress line is climbing, it's almost never because you have "too many users". It's usually one of five patterns: screens that load whole tables, images served at full size, files downloaded again and again without a cache, realtime subscriptions that broadcast too much, or a backend job pulling data through the pooler on a loop. This guide shows you how to find which one you have in about 20 minutes, using only the Supabase dashboard, and what to change first.

If you'd rather have someone read the bill with you, our Supabase bill review goes line by line through egress, compute and disk, and models the change before anything moves. If you want to understand it yourself first, read on.

What counts as Supabase egress

Supabase's own docs define egress as "network data transmitted out of the system to a connected client", and it comes from every service, not just the database. On the usage page you'll see it split into these sources:

  • Database egress: rows returned through the API your app uses (PostgREST, which is what supabase.from('table').select() talks to).
  • Shared pooler egress: rows returned through the connection pooler (Supavisor), usually from a backend, a script or an AI agent connecting with a database URL. Supabase doesn't count this twice; it shows up here instead of under database egress.
  • Auth egress: sign-in, sign-up and session refresh responses.
  • Storage egress: files and images downloaded from your buckets.
  • Edge Functions egress: responses your functions send back.
  • Realtime egress: messages pushed to subscribed clients.
  • Log drain egress: logs sent to an outside logging tool.

There is also cached egress, which is storage served from Supabase's CDN on a cache hit. Cached and uncached egress have separate quotas and separate rates, so moving file traffic onto the cache can matter even before you reduce the total.

Two details trip founders up. First, the quota is shared across all services for the whole organisation, so a busy test project or preview branch eats into the same allowance as production. Second, egress already served can't be reduced afterwards: fixes only lower next cycle's number. That's why it pays to find the cause early in the month.

Why AI-built apps run up egress

Tools like Lovable, Bolt and Cursor write code that works, and "works" is the goal they optimise for. Bandwidth isn't. The same habits show up in project after project:

1. **select('*') everywhere. The generated query asks for every column, including long text fields, JSON blobs and embedded arrays, even when the screen shows a name and a date. 2. No pagination. A list page fetches every row, then the browser shows the first 20. With 200 rows nobody notices. With 50,000 rows, every page view downloads the whole table. 3. Fetch on every render. A component re-queries each time it re-renders or the tab regains focus, so one person browsing for ten minutes triggers hundreds of identical requests. 4. Original-size images. A user uploads a 6 MB phone photo and the app shows it as a 64-pixel avatar, downloading the full file each time. 5. Realtime on a whole table. The app subscribes to every change on a busy table, so each update is pushed to every open tab, including changes the user will never see. 6. Agents and scripts reading through the pooler.** A sync job or AI agent pulls "all orders" every few minutes to check for anything new.

None of these are bugs in the usual sense. The app looks fine. The bill is the only symptom.

The 20-minute Supabase egress check

You need dashboard access to the organisation. Nothing below changes your data.

Step 1 (3 minutes): Find the service

Open Organization → Usage, pick the project, and look at the Total Egress chart. Hover over the biggest days to see the split by service. Write down which service dominates: database, storage, realtime, pooler, auth or functions. Also check whether preview branches have their own egress; Supabase records branch egress separately from the parent project.

Step 2 (3 minutes): Match the spikes to events

Look at the shape. A flat, steady line usually means a design pattern (every page view is heavy). Sharp spikes usually mean an event: a newsletter, a launch post, a bot, a cron job or a bulk export. Note the dates and compare them with what you did that day.

Step 3 (5 minutes): If it's database egress, find the heavy queries

Open Advisors → Query performance. Sort by calls and look at the average rows returned. A query that runs thousands of times and returns hundreds of rows each time is your prime suspect. Also look for queries that select every column from a wide table.

Then open Logs → Explorer, choose the API gateway source, and look at which paths are requested most. A single /rest/v1/ path dominating the list tells you which screen to look at.

Step 4 (4 minutes): If it's storage egress, check file sizes and caching

Open Storage, sort a bucket by size, and look at what users actually upload. Then open your live app with the browser's developer tools (Network tab, filter by "Img") and reload a busy page. Compare the size of each downloaded image with how big it appears on screen. If a thumbnail is several megabytes, you've found the leak.

Step 5 (3 minutes): If it's realtime, list your subscriptions

Search your code for .channel( and postgres_changes. For each one, check whether it filters by user or record (for example filter: 'room_id=eq.123') or listens to the whole table. Whole-table subscriptions on busy tables are the usual realtime culprit.

Step 6 (2 minutes): Check the Spend Cap and alerts

Open Organization → Billing and confirm whether the Spend Cap is on. Supabase's cost-control docs explain that with the cap on, usage beyond the quota for covered items is restricted rather than billed; with it off, the project keeps running and the overage is charged. Neither is "right". The point is to choose deliberately, and to make sure the billing email goes to someone who reads it.

What to change first, in order

Fix the cheapest, safest things first. Most apps need only the first three.

1. Ask for only the columns the screen shows

Replace select('*') with the columns the page needs, such as select('id, title, created_at'). Supabase lists "reduce the number of fields or entries selected" as its first optimisation. This change rarely breaks anything visible and often cuts database egress sharply on list pages. Ask your AI builder to do it screen by screen, and test each screen after.

2. Paginate every list

Add .range(0, 19) (or your page size) to list queries and load more on scroll or with a "next" button. Also stop inserts and updates from returning the whole row when the app doesn't use it.

3. Resize and cache images

Serve thumbnails, not originals. Supabase Storage offers image transformations on paid plans, which let you request a smaller width and lower quality from the same file. Make sure public, rarely changing files are served with sensible cache headers so repeat views can come from the CDN as cached egress rather than full uncached downloads.

4. Stop re-fetching the same data

Use a data-fetching library's caching (React Query, SWR) or a simple in-memory cache so the same list isn't requested on every render or tab focus. This lowers both egress and database load.

5. Narrow realtime

Filter subscriptions to the record or user that matters, and unsubscribe when a screen closes. If a screen only needs to know "something changed", send a small signal and fetch the detail on demand.

6. Move bulk jobs off the hot path

If a sync job or agent reads through the pooler, change it to ask for "rows changed since the last run" instead of everything. Schedule exports for off-peak times and compress them where the destination supports it. If you run a log drain, Supabase notes that turning on GZIP can reduce its egress.

Your Supabase egress checklist

  • Biggest egress source identified. Where to look: Organization → Usage. Healthy sign: you can name one service and one screen or job.
  • **No select('*') on list screens**. Where to look: Code search. Healthy sign: each query names its columns.
  • Lists are paginated. Where to look: Code search for .range(. Healthy sign: no list loads more than one page.
  • Images are resized. Where to look: Browser Network tab. Healthy sign: thumbnails are a small fraction of the original.
  • Realtime filtered. Where to look: Code search for .channel(. Healthy sign: every subscription has a filter.
  • Background jobs incremental. Where to look: Job code / pooler egress. Healthy sign: jobs read changes, not full tables.
  • Preview branches tidy. Where to look: Usage → branch list. Healthy sign: no forgotten branch with steady egress.
  • Spend Cap decided. Where to look: Billing. Healthy sign: a deliberate choice and a monitored billing email.

When egress isn't the real problem

Sometimes egress is the loudest line but not the one to fix first. If compute is oversized for the app, or the database is slow because a missing index makes every request heavy, fixing those can change the whole bill. And sometimes the honest answer is that your traffic is real and growing, which is a good problem. At that point the question becomes whether managed hosting still fits. Our guide to what self-hosting Supabase actually includes covers what you take on if you move, and why staying is often the better call. If your front end runs on Vercel, the same "find the line, then the cause" approach applies to the Vercel usage lines that grow fastest.

Before you change anything, it's worth running the free launch-ready self-check. Several of the patterns that inflate egress, like loading whole tables into the browser, are also privacy problems: if a screen downloads every row, it may be downloading rows that user shouldn't see.

Practical takeaways

  • Egress is data leaving Supabase, from every service, against one shared organisation quota.
  • Find the service first, then the screen or job. Guessing wastes time.
  • Column selection, pagination and image resizing fix most AI-built apps.
  • Fixes lower future egress only, so check early in the billing cycle.
  • Decide on the Spend Cap on purpose, and make sure billing emails reach a person.

FAQ

What is egress in Supabase?

It's the data Supabase sends out to clients: database rows, files, auth responses, function responses, realtime messages and log drain traffic. It's measured in gigabytes across the billing cycle, and you're charged only for usage above your plan's quota.

Why is my Supabase egress so high with few users?

Usually because each visit is heavy, not because there are many visits. A list that loads every row, a full-size image used as a thumbnail, or a background job reading the whole table every few minutes can use a lot of bandwidth with a handful of users.

Does caching reduce Supabase egress?

Caching in your app reduces requests, which lowers egress directly. Files served from Supabase's CDN on a cache hit are counted as cached egress, which has its own quota and rate, separate from uncached egress.

Will cutting egress break my app?

It can if done carelessly. Removing a column that a screen quietly relies on will show blank fields. Change one screen at a time, test it, and keep the change small.

---

Want a second pair of eyes on the bill? Our reduce Supabase bill review reads your egress, compute and disk lines, names the screens and jobs behind them, and shows the expected effect before anything changes. Book a free technical assessment and we'll tell you where your bandwidth is going.

Sources

Related posts

Next step

Book a free technical assessment.

Thirty minutes. We look at where you are, whether you are about to build, ready to launch, or already live, and tell you what matters first. You leave with a written next step, whether or not you hire us.

Every price is a custom quote after your assessment. No work starts until you accept the proposal.