Check these first
Sixty seconds, no AI. Most people are fixed by one of these and never need the prompt below.
- 1
Ask one question of your current design: can a signed-in user change the thing your rules trust? If tenancy depends on
user.roleor a field inuser.data, and the client can write to those, you do not have tenant isolation — you have a suggestion. A builder reported exactly this in the Base44 Discord on 14 Sep: "an authenticated non-admin user can callUser.update(self, {role: \"admin\"}), after which entity RLS using user.role treats them as admin." - 2
Check whether your tenant boundary is a data model or a UI convention. If the only thing stopping user B seeing tenant A's records is that the interface does not offer a link to them, it is not a boundary. The API is still there.
- 3
Test it with two accounts in two tenants. Create org A with user A, org B with user B, one record each. Sign in as B. Query the entity directly. This is the whole test and it takes five minutes.
- 4
Remember rules are OR. From the docs: "If a person matches any one rule, they get access." A strict tenant rule sitting beside a permissive one does not narrow anything — the permissive one wins.
- 5
Know what
user_conditioncan and cannot do. It is equality only — no$gt,$ltor$regex. Anything conditional, hierarchical or role-tiered has to be enforced in a backend function, not in a rule. - 6
Check whether permissions are per-table. They are. There is no partial-row visibility at the rule level, so "this team sees these columns" is a schema decision — split the entity — not a rule you can write.
Set this in your dashboard
Set the Membership entity to no client writes at all. create, update and delete all false. Memberships change through a backend function or they do not change. This is the single most important setting on the page, and it is the one people skip because it makes their first invite flow harder to build.
Do not use the built-in User entity for tenancy. It cannot carry your rules, and the client can write to parts of it. Use it for identity and nothing else.
Decide whether the app is Public before you design. Public means anyone can self-register. That is fine for a product with self-serve signup and fatal if you assumed only invited people exist — because your tenant rules will be tested by strangers, not just by your customers.
Split entities rather than trying to hide columns. Permissions apply to whole tables. If part of a record should be visible to a tenant member and part only to an admin, that is two entities.
Backend functions are Builder plan and above. If your architecture needs server-enforced logic — and a real multi-tenant app does — that is a floor on your plan, not a nice-to-have.
Why this happens on Base44
The multi-tenant guides that exist stop exactly where the hard part starts. They will tell you that the tenant model has to be a data model rather than a UI convention, which is true, and then not show you the schema. Here is the actual shape.
The problem to design around: on a public app anyone can self-register, the built-in User entity cannot carry your own access rules, and anything the client can write to — user.role, user.data.org_id — is not a security boundary. So you cannot store tenancy on the user. That single constraint determines the whole architecture.
The shape that works:
Organisation— the tenant. Name, plan, status. Created by a backend function, never directly by a client.Membership— the join:user_email,organisation_id,role. This is the record that decides everything, and the client must have no write access to it at all. Create, update and delete arefalseat the rule level; the only way a membership changes is through a backend function running as the service role, which checks that the caller is already an admin of that organisation before it writes.- Everything else carries
organisation_id, and its rules scope to memberships the caller holds.
The two traps. First, user_condition is equality-only, so "is this person an admin of the org that owns this record" is not expressible as a rule — that logic belongs in a backend function and the entity's own rules should be conservative. Second, a backend function is anonymous over direct HTTP unless you check, so every function that touches tenant data needs its own authentication check as its first act.
The honest caveat. Base44 does not publish a canonical multi-tenant reference. Two builders raised tenant-isolation failures in the Discord in one week, one having reproduced a failure of the documented pattern with synthetic data. Treat any architecture here — including this one — as something to test adversarially rather than trust.
Then run this
Paste into your Base44 builder chat. The first one only reads — it changes nothing, so it is safe to run on a live app.
Open Base44, opens in a new tabBase44 links on this page are affiliate links. If you sign up through one, Dean may earn a commission at no extra cost to you.The tenancy audit — read only, changes nothing
Audit this Base44 project's tenant isolation. I need to know whether a user in
one organisation can reach another organisation's data.
READ ONLY. Do not edit, create or delete any file, entity, schema or record. Do
not change an access rule. If something should change, describe it.
EVIDENCE RULE
Every finding carries [SCHEMA] entity + quoted rule, [CODE] file:line, or
[UNVERIFIED]. No PASS without evidence. Assume nothing is enforced unless you can
quote the thing enforcing it. Do not print record contents.
1. WHERE DOES TENANCY LIVE
- Is there an organisation/workspace/account/team entity? Name it.
- Is there a separate membership or join entity linking users to it?
- Or is tenancy stored on the user — user.role, user.data.org_id, or similar?
If so, say plainly that this is client-editable and therefore not a
boundary, and make it finding number one.
…60 lines · 2,907 characters
The build prompt — the membership model, done properly
Using the audit, implement server-enforced tenancy. This turn writes. STOP AND SHOW ME THE PLAN FIRST if this project currently stores tenancy on the user. Migrating from user-field tenancy to membership tenancy touches every rule and every query, and I want to see the plan before you start, not after. THE MODEL TO BUILD Organisation — the tenant. Client create: false. Created only by a backend function. Membership — user_email, organisation_id, role. Client create, update and delete ALL false. No exceptions. Changes happen through a backend function running as service role that first verifies the caller is an admin of that same organisation. Every tenant-scoped entity — carries organisation_id, rules scope reads and writes to the caller's membership. RULES FOR THE WORK - Never write a rule that trusts user.role or user.data for tenancy. …
43 lines · 1,998 characters
Run this only after you have read the audit above, and only when you are happy for it to change files.
The adversarial test — try to break your own tenancy
Try to defeat the tenant isolation you just built. Be adversarial, not reassuring. I would rather you find it than a customer does. For each attack below: can it succeed? Quote the rule or the code that stops it, or say UNVERIFIED. "It should be fine" is not an answer. 1. A signed-in user calls update on their own User record, setting role to admin. What stops entity rules from then treating them as an admin? 2. A signed-in user creates a Membership row for themselves in an organisation they do not belong to. What stops it? 3. A signed-in user updates an existing Membership row, changing their role from member to owner. What stops it? 4. A signed-in user calls a backend function with an organisation_id belonging to someone else. Which line verifies their membership before acting? 5. A signed-in user queries a tenant-scoped entity directly through the API rather than through your UI. Which rule limits what comes back? 6. Someone with no account at all queries each tenant-scoped entity, and each backend function, unauthenticated. What do they get? …
31 lines · 1,864 characters
An agent that reports its own work as done is not evidence. This pass re-checks from outside the change.
What this can’t fix
Run the two-tenant test yourself. Two organisations, two users, one record each, then try to cross the line from the wrong account. An agent cannot do this — it has no second identity — and it is the only test that actually proves the model.
Design the invite flow before you build the app. How someone joins a tenant is where most isolation bugs live, and retrofitting it is painful because every existing record already has an owner. Decide now: who can invite, what happens on accept, and what happens on removal.
Decide what happens to data when someone leaves. Removing a membership should remove access immediately — check whether your deletes are soft, because a soft-deleted membership that still matches a rule is not a removal.
Do not rely on the security scan to validate this. It checks for missing rules, not for a tenancy model that is coherent. A green scan on a design that trusts user.role is a green scan on a hole.
Be realistic about whether you should be building this on conversational prompting at all. Multi-tenant SaaS with real customer data is the point at which the cost of getting it wrong exceeds the cost of having someone experienced look at it once. An hour of review before launch is cheaper than a breach notification after.
Links you’ll need
- Base44 — entity security referenceRule syntax and the worked owner-only example.
- Base44 — RLS examplesuser_condition is equality only — no $gt, $lt or $regex. Anything conditional needs a backend function.
- Base44 — managing security settings"If a person matches any one rule, they get access." Rules are OR. And permissions apply to whole tables.
- Base44 — backend functionsWhere server-enforced logic lives, and what asServiceRole does.
- Base44 — managing accessOn a Public app "anyone can create an account from your register page and sign in".
Asked in the Base44 Discord, 14 Sept 2026. Facts on this page verified 15 Sept 2026. v1. Google and Base44 both change things — if something here has gone stale, tell me.