Home

Comparison

Supabase vs CustomAPIs for multi-tenant APIs

Both are built on Postgres, and both support multi-tenancy. The difference shows up immediately: on one it has to be built, on the other it is part of the framework.

Supabase and CustomAPIs have important things in common. Both build on Postgres. Both expose database-backed functionality through API routes. Both are capable platforms for real applications.

The distinction matters when the API supports a multi-tenant business system: organisations, divisions, locations, users with different roles, approval workflows, audit requirements, and business actions beyond creating and editing rows. Users hold different permissions in different tenants, and business rules govern what they may do as well as which data they may see.

Supabase is a broad, highly extensible platform built around a generated data API over Postgres. CustomAPIs is a framework for building multi-tenant application APIs — tenant isolation, permission scope, audit and business operations in one layer.

You can, of course, write your own multi-tenant API layer in front of Supabase. That is a sound architecture. But then the question isn't Supabase versus anything — it's whether you build tenant scope, permission resolution, audit and events yourself or start with them, which is a separate discussion. This article compares the two platforms as you would actually adopt them.

Where the two agree

The disagreement is narrower than a comparison usually implies. Both approaches start from the same convictions:

  • Standard API behaviour should be declarative. Repetitive routes should come from a data model rather than from developers hand-writing similar endpoints.
  • The data model is central. Routes, validation and documentation should derive from one description of entities and their relationships.
  • Relational modelling suits business systems. Organisations, users, roles, records and workflows naturally relate to one another.
  • Consistency should be structural. Generated behaviour beats conventions that every developer has to remember and apply by hand.

They differ in what they carry, and how far. Supabase carries the schema into a generated data API, and provides flexible platform capabilities around it. CustomAPIs carries the model into the application API layer.

Three steps to a tenant-scoped route

In CustomAPIs, making a resource available to the right people is three steps:

  1. Create the table

    Your schema, with a foreign-key path from the record to its tenant.

  2. Declare the route

    f.route({ model: 'employees', operation: 'get' });

  3. Grant the permission

    Add app_get_employees to a role in access management.

There is no fourth step for tenant isolation. The framework reads the foreign-key path from the record to the tenant and applies that scope to every route on the resource — the live demo answers one endpoint three ways from three keys in the same company, with no filtering code in the application.

The same three steps in Supabase look like this:

The three steps compared between Supabase and CustomAPIs
StepSupabaseCustomAPIs
Create the tableCreate the tableCreate the table
Make the route available Expose the table through the Data API, then configure grants and RLS before clients can reach the intended rows One line per operation naming the model and the operation
Restrict it to the caller's tenant Write an RLS policy expressing the path to the tenant, for each operation Derived from the foreign-key path — no step
Let a user perform it Build a roles and permissions model, then encode it in policy SQL and JWT claimsAdd app_get_employees to the user's role

The first row is identical on purpose. Neither approach removes the work of modelling the relationship — the question is how many times you have to restate it.

The same resource, both ways

Take line items on an invoice, four levels down from the tenant: organisation → project → invoice → line item. Full CRUD in CustomAPIs, against the select case alone in Supabase:

CustomAPIs — five routes

f.route({ model: 'line_items', operation: 'get' });
f.route({ model: 'line_items', operation: 'search' });
f.route({ model: 'line_items', operation: 'create' });
f.route({ model: 'line_items', operation: 'update' });
f.route({ model: 'line_items', operation: 'delete' });

Then grant app_get_line_items and its siblings to the roles that should hold them.

Supabase — the select case alone

alter table line_items enable row level security;
grant select, insert, update, delete
  on line_items to authenticated;

create policy "line_items_select" on line_items
  for select to authenticated
using (
  exists (
    select 1 from invoices i
    join projects p on p.id = i.project_id
    join user_organisations uo
      on uo.organisation_id = p.organisation_id
    where i.id = line_items.invoice_id
      and uo.user_id = auth.uid()
  )
);

This is one policy of four. insert needs a with check, update needs both clauses, delete its own using. Teams may also factor a recurring check like this into a carefully designed security definer helper: it simplifies the policy and avoids re-planning the join for every row, but it is more code to write, index and maintain, and a helper that bypasses row security by design carries security considerations of its own.

Five lines and a role grant, against roughly forty lines of SQL and four policy tests. Per table.

Foreign key enforcement

Relationships introduce a second enforcement problem, and it starts the same way for both approaches. Postgres validates foreign keys with row security deliberately bypassed — the Postgres documentation is explicit that referential integrity checks always bypass row security so that integrity is maintained.

A foreign key pointing at another tenant's row is a valid foreign key.

Nothing in the constraint stops a user in one organisation attaching a line item to another organisation's invoice. Enabling row security on the related tables does not close it either — the constraint check never consults those policies. Unless the schema adds a tenant-aware constraint — a composite key carrying the tenant column, or a trigger — the rule has to be enforced at the point of the write.

The case for Supabase

Anything you can write in SQL.

The enforcement point is precise: with check, on insert and on update. It is a general extension point — the tenancy condition, a foreign key confined to the caller's own records, a requirement that the invoice is in draft or that the caller holds a finance role, all expressible in one clause. It is visible in the schema, auditable and testable on its own terms. And it sits in the database, so a correct policy holds against anything that reaches the data, including an application bug or a second client — a real security property that no API-layer check matches.

The cost is that this logic must be designed, written and tested for every exposed table and operation — and that the tenancy boundary ends up in the same clause as the business rules, so is our tenancy correct? cannot be answered without reading the workflow conditions threaded through it. update needs both using and with check; with only the first, a user can re-point a record they legitimately own at a tenant they do not. Omissions do not fail loudly.

The case for CustomAPIs

There is nothing to write.

The framework already has the path to the tenant, so it gates the record on a write as well as a read — and records cannot be moved across tenants by update, closing the re-pointing case above by construction.

The cost: enforcement sits a step away from the database, and resolving scope can cost an extra call. And it covers the framework's own query paths — conditional rules and custom operations are application code, which has to enforce tenancy itself and be rigorously tested for it.

The trade is between enforcement that sits closest to the data and enforcement that cannot be forgotten. Neither location makes a wrong rule right — a mistaken policy is enforced as faithfully as a correct one. What differs is how many rules there are to get right, and whether a missing one announces itself.

Multi-tenancy is more than a tenant ID

A multi-tenant application needs more than a tenant column. Every read, search, create, update and delete must respect the caller's permitted scope — and that stays true when data is reached through related records, custom operations, views, background processes and events.

Row Level Security is genuinely powerful; its policies can express sophisticated access logic in SQL. But applying it across a multi-tenant application is substantial work. For each exposed table you consider the relationship to the tenant, write the policy logic, decide which operations are allowed, and test the result. Supabase's own RLS guidance recommends configuring grants and policies for every exposed table, defining them per operation, and testing what comes out.

The modelling work does not disappear under CustomAPIs. You still connect each resource to its tenant, directly or through a relationship path. What disappears is translating that relationship into policy SQL for every table and every operation, and keeping the two in step for the life of the system.

Row filtering is not access management

RLS answers one important question: which rows may this request touch? A multi-tenant business application also has to manage the rules that produce that answer.

  • Which organisations, divisions and locations exist?
  • Which users belong to them, and which roles do they hold at each level?
  • Which permissions does each role carry?
  • Who can grant, revoke and audit access?
  • How does this integrate with an access-management model the business already runs?
  • How are the same permissions applied consistently across more than one API?

Supabase provides the primitives to build all of it — tables, claims, functions, policies. But the access-management model, its administration experience and its integration with the rest of the business are yours to design, build and maintain.

CustomAPIs has a separate Access Management control plane for tenancy structures, users, roles, permissions and grants. The API resolves the caller's permitted scope from it and applies that scope consistently. Where a customer already runs an internal access-management model, the integration point is designed to be shaped around their organisation structure and permission rules rather than pushed down into table-by-table policy SQL.

This is the row in the table above that reads build a roles and permissions model. It is a substantial body of application work.

CRUD is only part of a business API

Generated table routes are useful, and business applications immediately need more than them: submit, approve, publish, allocate, close, reverse. Records carry a status lifecycle, and access is often conditional on it — a partner sees approved records but not drafts.

Supabase supports this. Depending on the design you reach for database functions and RPC, Edge Functions, triggers, or an application API in front. That is a normal architecture, and in many production systems Supabase settles into being a capable database, auth and realtime layer behind one.

CustomAPIs is intended to be that layer. Standard routes and business-specific operations live in the same framework, under the same tenant scope, permissions, validation and audit behaviour. A state transition, its permission check, its audit record and the event it emits are part of one API operation rather than four things wired together. Supabase offers database webhooks and Realtime for distributing database changes; CustomAPIs emits committed-write application events to the customer's chosen infrastructure.

None of which makes business rules disappear. They stay ordinary application code, because they are genuinely specific to the business. What stops recurring is rebuilding the common API concerns around each new operation.

Managed Postgres is a commodity

Supabase manages the database for you, which is a real convenience. It is also not scarce. Managed Postgres is a mature market — Aurora, RDS, Cloud SQL, Neon and others — with options offering more operational control and a clearer path when you outgrow the tier you are on. CustomAPIs runs against your own Postgres wherever you choose to put it, which keeps the database decision independent of the API decision.

The obvious objection

There is a real question in picking a specialised framework over a large platform, and it deserves a straight answer rather than a paragraph of reassurance. CustomAPIs is a smaller company than Supabase.

What limits the exposure is what you keep. The database is yours, on infrastructure you control, in a schema you own. Business logic is ordinary application code. The framework removes repetition around your model — it does not hold your data or your deployment. What that means in writing is set out in the ownership, licence and continuity terms.

Which approach fits

Start with who will operate it. Supabase can be managed through its web interface to a large degree, which suits a team whose strength is SQL and Postgres. CustomAPIs is a Node package with a declarative surface, which suits a team that works in TypeScript and wants the API declared in code it reviews and versions. Either way the multi-tenancy itself is expert work — a dashboard changes where you write the policy, not what it takes to get it right.

When each approach fits
Supabase fits when…CustomAPIs fits when…
Your team's strength is SQL and Postgres, and a web interface for schema, auth and inspection is an advantageYour team works in Node and TypeScript, and wants the API surface declared in code it reviews and versions
You want one vendor for database, auth, storage, realtime and hosting You don't want to write tenant isolation, and you want to get started quickly
Clients talk directly to the data API and that suits the application Business operations and CRUD must share one permission model
The access model is still moving while you find product shape There is an in-house access-management model to integrate
The team has no appetite for running infrastructure Audit and committed-write events are part of the API contract
CRUD needs little customisation You want control of the database, hosting and deployment

The first two rows on the left are real reasons a good team picks Supabase and never regrets it.

The actual decision

The choice is not between generated routes and hand-written ones. In a multi-tenant business system you will need both standard data access and business-specific operations, whichever platform you start from.

Supabase gives you Postgres, a generated data API and a set of genuinely powerful primitives, and asks you to compose tenancy, permission scope and audit out of them. CustomAPIs gives you those three as the foundation and asks you to model your tenancy relationships properly. Both are real offers. Six questions separate them, and none of them is about whether the platform can do it.

  • Who will operate it? Supabase is administered largely through a web interface, but multi-tenancy is policy SQL wherever you type it — the dashboard changes the surface, not the expertise. CustomAPIs is a Node package inside your service, so whoever maintains the API is whoever writes TypeScript.
  • How long until it works? Three steps per resource, against grants, four policies, a helper function and their tests — for every table you expose.
  • How hard will it be to maintain? Access rules derived from the model move when the model moves. Access rules spread across tables, policies and tests have to be kept in step by hand — increasingly by people who did not write them.
  • Will it still fit? When the organisation model changes — a division level added, a new role, a partner tier — is that a change to access-management configuration, or a pass over every policy and every test?
  • Does it leave you an architecture to build on? The second API that needs the same permissions, the integration with an access-management model the business already runs, the committed-write events other systems consume.
  • Can it scale far enough? The database ceiling matters, and so does whether you can move when you reach it — which depends a good deal on whose infrastructure it is sitting on.

Capable teams can build all of this on Supabase. That was never the question.

Sources

Statements about Supabase were checked against its public documentation in September 2026. Supabase is a trademark of Supabase Inc.; we are not affiliated with, endorsed by or a reseller of Supabase. Supabase ships quickly — if something here has gone out of date, tell us and we will correct it.

Do you want a multi-tenant API out of the box?