One row in the organizations table is one building company. Every tenant-scoped table in the database carries an org_id column, every request resolves exactly one acting org, and every read and write is filtered to it server-side. The account has a slug that becomes a subdomain, an owner, a plan, a status, and its own branding, settings, pricing, crews, contacts and money.
Also called: sub-account · multi-tenant · separate company account · my own dashboard · tenant
- 1Migration 013 created the organizations table and added an org_id column to every tenant-scoped table.
- 2The request host is resolved to an org: subdomain first (acme.leads2build.com), then verified custom domain.
- 3Middleware stamps x-org-id / x-org-slug onto the request so every downstream route knows which company it is serving.
- 4serverAuth.getAuthedUser resolves the acting org with a fixed precedence: impersonation target, subdomain, the user's own metadata org, then the linked Clerk organization.
- 5The /api/db proxy stamps that org_id onto every row written and appends .eq('org_id', …) to every row read.
The product started as one builder's dashboard, so 'the company' was implicit — it was whoever was logged in. Migration 013's header states the transition plainly: existing rows backfill to 'org_default' (the first account) 'so nothing breaks before the rest of the multi-tenant code lands.' Everything else in this domain exists because that transitional assumption kept resurfacing as a bug: a default org that silently caught rows, a URL that was trusted over a membership check, a cache that outlived a switch. serverAuth still carries the original note — orgId 'falls back to org_default … keeps the single-tenant flow working' — with the fallback now restricted to the platform owner alone, because for anyone else it meant landing in another company's data.
- Two builders on one platform must never see each other's leads, prices, crews or money.
- A single-tenant app can't be sold to a second customer without a boundary that the code enforces on every query.
- Data written without a company stamp silently lands in whichever account the column default points at.
See it on your own jobs
Twenty minutes, your numbers, no slide deck. We’ll build one of your real buildings in front of you and send you the estimate link at the end — yours to keep either way.
or keep browsing features →