Six ideas, one account per vendor
Every idea wants its own Vercel project, Supabase project and Stripe account. One account per vendor was the fix, and the smaller bill was a side effect.
· 8 min read
Four Supabase projects, one per product, because that is the default path in every dashboard and each one took ten seconds to create. In July they came to $59.74 for the month.
Fifty nine dollars is not a crisis. That is the point. It was not a crisis the month before, and it would not have been one the month after, and that is how this sort of cost survives. It is never quite annoying enough to fix.
The bill is not really what this is about. It is the only part of the problem that arrives on a statement, which is why it is the one people argue over, and it is the smallest. The expensive parts were the credentials, the dashboards, and the copies of auth and billing I was keeping in step by hand, and none of those turn up on an invoice.
The advice assumes you are building one thing
Almost everything written about shipping small software assumes a single product. Pick a stack, launch, talk to users, iterate. Fine advice for that case.
It also assumes your fixed costs are fixed. If you run several products they are not fixed. They are per product, and most of them arrive before the product has a single user:
- a Vercel project
- a Supabase project
- a Stripe account, or at minimum a separate catalog and webhook endpoint
- auth: sign in, sign up, reset, MFA, invites, a settings page
- billing: checkout, customer portal, webhook handling, entitlement checks
- transactional email with a verified sending domain
- an analytics project
- somewhere to put privacy, terms, and refunds
- a line in the bookkeeping, and a decision about whether it needs its own entity
Call it a week of work and a monthly bill in the tens of dollars, per product, indefinitely. Six of those is six weeks spent building nothing anyone asked for, plus a standing charge for the privilege.
Your framework choice does not move that number. Consolidating the overhead moves all of it.
One account per vendor, not one per product
The fix is unglamorous. For each vendor you keep one account, and the products live inside it as tenants.
Supabase is the clearest case. Four projects became one project: $59.74 a month down to $25. Each product got a schema of its own inside the same database, with the genuinely shared things (organizations, members, subscriptions, brands, domains, audit events) in a core schema that all of them read. The products do not share tables. They share a database.
I stayed on Pro rather than dropping to the free tier, deliberately. Free has no daily backups, and there is real customer data in there. Twenty five dollars for a database I can restore is not the place to economize. Consolidating is about paying for something once, not about paying nothing.
Vercel got the same treatment: one Pro team hosting every product, instead of a team per product. Domains attach to projects. Teams are the thing priced per seat, and I am the same seat six times over.
The option I turned down
I looked hard at Neon. On the raw Postgres line it is cheaper, and for a couple of weeks I had a plan to move.
I did not move, because the apps do not use Postgres. They use Supabase. Authentication is Supabase Auth, and a good deal of the data access goes through PostgREST with row level security doing the authorization. Swapping in cheaper Postgres would have meant rebuilding auth and rewriting the data layer, then owning both of those forever, to save less per month than the rebuild would have cost me in a single evening.
Cheaper Postgres is not a drop-in replacement for a platform. Worth saying out loud, because that comparison turns up in every cost thread, always on price per gigabyte and never on what you would have to rebuild.
The parts that are not a hosting bill
Consolidation is not only infrastructure.
There is one LLC over the whole portfolio, Hamma Ridge Ventures. Not one per product. Each product is a line of revenue, not a company. One registered agent, one tax return, one bank account, one set of renewals.
Bookkeeping went the same way. I was paying $25 a month for Xero to categorize roughly 350 transactions a year. That is about 85 cents per transaction, for software built to run a business with employees, invoices, and inventory. Mercury already categorizes transactions; adding GL codes to those categories produced everything my accountant needed, and the Xero subscription went away. Xero is a good product. It was a good product for someone else.
The codebase has to be the same shape as the business
This is where it stops being a procurement exercise.
If the business is one entity with several products inside it, and the infrastructure is one account per vendor with several tenants inside it, then a codebase split into six repositories is fighting both. Every shared fix gets applied six times, or four times and then forgotten twice. The auth flow in the newest app is the one you wrote last, so it is the good one, and the other five quietly rot.
So the products live in one application. Two ideas carry most of the weight.
The first is resolving the tenant from the host. A request arrives, the host is matched against a table of domains, and that one lookup yields the product, the organization, and the brand for the rest of the request. Everything downstream reads the resolved value instead of asking again. Products stop being deployments and start being rows.
The second is treating a brand as data rather than as code. Colors, fonts, corner radius, logo, email theme: a row, not a fork. Two products that look nothing alike run the same components, and the difference is which row loaded. That is the one I took longest to believe, because it sounds like a recipe for mush. In practice it goes the other way. A component that has been through an accessibility pass and six products of real use beats six bespoke ones, every time.
Neither idea is hard to describe. Both are a lot of work to build properly, and almost all of that work is in the parts nobody demos: what happens on an unknown host, how the content security policy varies per tenant, keeping one organization's rows unreachable from another's, making sure a session refresh cannot leak across brands. I have got each of those wrong at least once.
The seventh product
The test of all this was adding the next one.
The seventh product needed three things: an entry in the product list, one registration call, and its own database schema. It inherited auth, billing, transactional email, analytics, the component kit, the cron dispatcher, and the deploy. No new Vercel project. No new Supabase project. No new Stripe account. No new week.
Privacy and terms are the one qualified case. The policy copy is a shared component that takes the brand name, so it themes itself, but each product still mounts its own two route files over it. That is two small files, and the only part of the list I had to write myself.
That is the point of the shape. Not that the overhead is cheap, but that you set it up once and fix it once.
What it costs you
The honest ledger, in the other direction.
One database means one blast radius. A bad migration is bad for everything. Migrations deploy through CI only, never from my laptop, and the local suite has to be green first, because the alternative is one bad afternoon multiplied by six.
One deploy means one deploy. A build break stops the portfolio, so type errors and lint failures fail the build rather than getting waved through on a Friday.
And isolation between products has to be enforced by something other than good intentions. Lint rules stop one product importing another. Row level security stops one organization reading another's data. Both are load bearing, and both are the kind of thing you only get right after getting it wrong.
I would take that trade again. Six weeks of setup and six standing bills buys a lot of tolerance for having to be careful.
The chassis I have been describing is the thing I now sell: millroom. Same code, running the products in this post. The dated cost line items live in running many products. What the consolidation actually bought was fewer accounts to open and fewer copies of the same code to keep patched.