See Pwas at work: 30 guided minutes on an application that already runs. Book the demo →
Compare products Pwas in your industry Book a demo
Pwas-One
ERPShopCRMDoc ManagerAI Agent
Pwas.FrameworkPwas.ClientPwas.OrchestratorPwas.Microservice
Pwas CLIAssessmefyDynamic Registry Builder
Solutions Industries Documentation Partners Request a demo Get Started
Italiano English
pwas.it — powered by pooel.it
solutions · multi-tenant SaaS

Tenant isolation is one line of config, not a rewrite.

Ownership-aware permissions and per-field, per-role visibility, resolved at runtime from the same schema that describes your entities — not a check hand-written into every endpoint.

the problem

Hand-written multi-tenancy is fragile multi-tenancy.

Every endpoint has to remember to filter by tenant, every new entity has to repeat the same ownership logic. With Pwas.Framework, conditional rules and per-field role visibility are declared once in the schema and hold for every operation, on every entity — including the ones you add next year.

why this is the critical point

The incident every SaaS founder fears, and why it's almost always the same one.

Loss of isolation in a multi-tenant SaaS almost never happens through an attack. It happens because someone wrote a new endpoint and didn't repeat the filter. A report added in a hurry, an export, a global search function written for internal support and later exposed. The code works perfectly: it does exactly what it says, and what it says is incomplete.

The structural reason is that in the traditional approach isolation is a convention every piece of code must honour, not a property of the system. You defend against it with code review, tests and discipline. Those are useful and insufficient defences: a tight deadline and a new developer are enough for one of them to give. And the damage, when it happens, isn't technical but contractual and reputational.

What changes when isolation is declared

In the declarative model, the rule that a record belongs to whoever created it — or to their tenant — isn't written in an endpoint: it's a condition declared on the entity. The engine applies it to every read and every write, whatever the path: internal screen, exposed interface, search, export, and even a plan compiled by an AI agent.

The practical difference is sharp. No new endpoint can forget the filter, because the filter isn't in the endpoint. Adding an entity next year means declaring who it belongs to, not remembering to replicate logic. Whoever writes a new function doesn't need to know the project's conventions to avoid doing damage.

Per-field visibility, which is the next level

Tenant isolation is the obvious requirement. What costs most in practice is the level below: within the same tenant, who sees which fields. The customer's administrator sees costs, the operator doesn't. The commercial contact sees the full record, the engineer only what they need for the job.

In the declarative model this is the same category of rule, expressed at single-field granularity, and it holds everywhere that field could appear. It's why projects starting with intricate permissions — typical in B2B where your customer has its own internal roles — reach production far faster than traditional experience would suggest.

the comparison

Hand-written isolation versus declared isolation.

Traditional application multi-tenancy

A convention everyone must remember

  • Every endpoint must apply the tenant filter, and can forget it.
  • Every new entity requires repeating the same ownership logic.
  • Per-field visibility is implemented screen by screen.
  • Exports and reports are where the filter most often slips.
  • Security depends on review, tests and team discipline.
  • An interface exposed to third parties needs a security review of its own.
Declared isolation in Pwas

A property of the system, not a convention

  • The ownership condition is declared on the entity and applied to every operation.
  • A new entity declares who it belongs to: there's no logic to replicate.
  • Visibility is declared per field and per role, valid wherever that field appears.
  • Exports, searches and reports all pass through the same authorisation engine.
  • Security doesn't depend on who writes the next piece of code.
  • Exposing an interface means declaring what it can see, not re-verifying everything.
how to start

From the model to the first tenant in production.

The path is the same whether you're at your first customer or have a hundred to migrate.

  1. 01

    We define what a tenant is for you

    It sounds obvious and almost never is: is a tenant the customer company, one of its sites, one of its projects? Can users belong to several tenants? Is there data shared between tenants? The answers determine everything else and must be given at the start.

  2. 02

    We declare ownership and roles

    For every entity, who it belongs to and which roles can do what with it. For every sensitive field, who sees it. It's the document that replaces the project's unwritten conventions.

  3. 03

    We build the functional core

    APIs, permissions, validation and screens come from the declarations. In this phase you work on the product, not on isolation infrastructure, because that's already given.

  4. 04

    Explicit isolation verification

    Before production we systematically verify that no path lets one tenant see another's data: reads, searches, exports, exposed interfaces. Because there's one engine, the verification is exhaustive rather than sampled.

  5. 05

    Onboarding and growth

    Adding a tenant is a configuration operation. Adding a feature doesn't require re-verifying isolation, because the new entity inherits the same mechanism.

multi-tenant

One product, tenants isolated by declaration.

Isolation, roles and per-tenant configuration are part of the model: adding a customer is a configuration change, not a new deployment.

AAAWgmp1bWIAAAAeanVtZGMycGEAEQAQgAAAqgA4m3EDYzJwYQAAABZcanVtYgAAAEdqdW1kYzJtYQARABCAAACqADibcQN1cm46YzJwYTo5YjQ3YWNiZS1lM2UxLTRkMGYtYWUwMi1lYWY4NWIyM2NlZDMAAAADl2p1bWIAAAApanVtZGMyYXMAEQAQgAAAqgA4m3EDYzJwYS5hc3NlcnRpb25zAAAAALxqdW1iAAAARGp1bWRjYm9yABEAEIAAAKoAOJtxE2MycGEuaW5ncmVkaWVudC52MwAAAAAYYzJzaIYOPrG0Bt0Wv2GfptjxVhoAAABwY2JvcqNpZGM6Zm9ybWF0bWltYWdlL3N2Zyt4bWxqaW5zdGFuY2VJRHgseG1wOmlpZDpmZTU4ZWM5Zi1mNGRlLTQyYTAtODQ4NC0wYjQwYTc3OGQ4OGVscmVsYXRpb25zaGlwaHBhcmVudE9mAAAB4mp1bWIAAABBanVtZGNib3IAEQAQgAAAqgA4m3ETYzJwYS5hY3Rpb25zLnYyAAAAABhjMnNoOkPB2Jj1ajgsa9/KFdyvdQAAAZljYm9yomdhY3Rpb25zgqJmYWN0aW9ua2MycGEub3BlbmVkanBhcmFtZXRlcnOha2luZ3JlZGllbnRzgaJjdXJseC1zZWxmI2p1bWJmPWMycGEuYXNzZXJ0aW9ucy9jMnBhLmluZ3JlZGllbnQudjNkaGFzaFggFII4O9qVM4cYlhtW7C3sSKhXVu6lup58VL459q7h+pykZmFjdGlvbngdY29tLmFudGhyb3BpYy5jbGF1ZGUucHJvdmlkZWRqcGFyYW1ldGVyc6F4H2NvbS5hbnRocm9waWMub3JpZ2luLWNvbmZpZGVuY2VndW5rbm93bmtkZXNjcmlwdGlvbnhmQ2xhdWRlIHByb3ZpZGVkIHRoaXMgZmlsZSBhdCB0aGUgcmVxdWVzdCBvZiBhIHVzZXIgYW5kIG1heSBoYXZlIGNyZWF0ZWQgb3IgbW9kaWZpZWQgdGhlIGZpbGUgY29udGVudHMubXNvZnR3YXJlQWdlbnShZG5hbWVmQ2xhdWRlcmFsbEFjdGlvbnNJbmNsdWRlZPUAAADIanVtYgAAAEBqdW1kY2JvcgARABCAAACqADibcRNjMnBhLmhhc2guZGF0YQAAAAAYYzJzaEvgUhaM6+ik8PKKNqnkI+kAAACAY2JvcqVjYWxnZnNoYTI1NmNwYWRNAAAAAAAAAAAAAAAAAGRoYXNoWCAb5xl+lV4VPQuPs1NaIfU+2Gg+O1OLHDw1yNiBXet1t2RuYW1lbmp1bWJmIG1hbmlmZXN0amV4Y2x1c2lvbnOBomVzdGFydBjvZmxlbmd0aBkeBAAAAj5qdW1iAAAAJ2p1bWRjMmNsABEAEIAAAKoAOJtxA2MycGEuY2xhaW0udjIAAAACD2Nib3KlY2FsZ2ZzaGEyNTZpc2lnbmF0dXJleE1zZWxmI2p1bWJmPS9jMnBhL3VybjpjMnBhOjliNDdhY2JlLWUzZTEtNGQwZi1hZTAyLWVhZjg1YjIzY2VkMy9jMnBhLnNpZ25hdHVyZWppbnN0YW5jZUlEeCx4bXA6aWlkOmJjYjNmMDQ4LWU5MTQtNDZmNi1hNTMzLThmYTNlNDA5ZmIwMXJjcmVhdGVkX2Fzc2VydGlvbnODomN1cmx4LXNlbGYjanVtYmY9YzJwYS5hc3NlcnRpb25zL2MycGEuaW5ncmVkaWVudC52M2RoYXNoWCAUgjg72pUzhxiWG1bsLexIqFdW7qW6nnxUvjn2ruH6nKJjdXJseCpzZWxmI2p1bWJmPWMycGEuYXNzZXJ0aW9ucy9jMnBhLmFjdGlvbnMudjJkaGFzaFgg9HLT9L4cfw4pV1hT7wtwf6wKkFMNcNwIipeBZ52BlpeiY3VybHgpc2VsZiNqdW1iZj1jMnBhLmFzc2VydGlvbnMvYzJwYS5oYXNoLmRhdGFkaGFzaFgghrz+p+/TwtmUcDfYvXRitdR2bveLLgNfBjm9P6Qv3pB0Y2xhaW1fZ2VuZXJhdG9yX2luZm+jZG5hbWVvQW50aHJvcGljIEZpbGVzZ3ZlcnNpb25lMS4wLjBrc3BlY1ZlcnNpb25lMi40LjAAABA4anVtYgAAAChqdW1kYzJjcwARABCAAACqADibcQNjMnBhLnNpZ25hdHVyZQAAABAIY2JvctKEWQISogEmGCFZAgowggIGMIIBjaADAgECAhRA5aAK7sI50L64g/oGQgU9Z1UTADAKBggqhkjOPQQDAzBJMRcwFQYDVQQKEw5BbnRocm9waWMsIFBCQzEuMCwGA1UEAxMlQW50aHJvcGljIENvbnRlbnQgQ3JlZGVudGlhbHMgUm9vdCBDQTAeFw0yNjA4MDcxODQzNTZaFw0yODA4MDYxOTQzNTZaMEQxFzAVBgNVBAoTDkFudGhyb3BpYywgUEJDMSkwJwYDVQQDEyBBbnRocm9waWMgQ2xhdWRlIENvbnRlbnQgU2lnbmluZzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJh6CmvLUBgFFNU0vUKlOVtE6djd17L5SuwX0LemFisBM3dkd/3cyjxFA3Qo5S46fX0/ihY0VZ7mfb9KF703t5OjWDBWMA4GA1UdDwEB/wQEAwIHgDAVBgNVHSUEDjAMBgorBgEEAYPoXgIBMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUzlHiBIFOZFsj+OPEz5o+nMHXXMIwCgYIKoZIzj0EAwMDZwAwZAIwMXMdFJ4BetLLVY7ORuE9noqbbAZOZn/aArXyTwFAZfKrPzxF2vPoJNf1+UCdg1XGAjBwX1zd9WGqYkqmL5SFqw1QySjr1zJfpJM9+1rdDwSPLMOPOjKuiXjoU/pUUeG9RwmhY3BhZFkNngAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPZYQBA97mMBD1GWcM2cohxbeplPe6OOYQHfptnLRlVrLQnMu55799+cqKqW5UgW2X51O3+bYtXzLbxmZh+hSZvr3pk=One product, many tenants, isolated by declarationA single declared model serves every tenant. Isolation, roles and per-tenant configuration are part of the declaration, so onboarding a new customer is a configuration change rather than a new deployment.MULTI-TENANT BY DECLARATIONCUSTOMERSTenant ATenant BTenant CShared modelONE PRODUCTTenant isolationDECLARED, NOT PATCHEDPer-tenant configBRANDING · RULES · PLANSOnboardingMINUTES, NOT RELEASESRESULTSeparate dataShared upgradesUsage per tenant
the guarantees

What is declared and what cannot break.

Engine properties, verifiable in a demo.

1
place where isolation is defined

The ownership condition is declared on the entity: there's no second place where someone could forget or contradict it.

per field
visibility granularity

Not just which records, but which attributes of that record each role can read or modify — and it holds everywhere the field appears.

every path
where the rule applies

Screens, searches, exports, exposed interfaces and AI-compiled plans all pass through the same authorisation engine.

config
adding a tenant

Onboarding a new customer requires no code changes and no dedicated security review.

These are platform properties, verifiable in a demo. They don't replace the security testing every SaaS product must still carry out, nor the obligations that fall to you as controller of your customers' data.

in depth

The questions from people building a product.

"Shared database or one database per tenant?"

The first architectural decision of any SaaS. There's no universal answer, but there are clear criteria.

Shared database with logical isolation is the right choice in the great majority of B2B cases: it costs less in infrastructure, makes schema updates trivial, and lets you add a customer with a configuration operation. Its one historic weakness is exactly what the declarative model fixes — the risk that some path forgets the filter.

One database per tenant makes sense where explicit contractual or regulatory requirements demand physical separation, where a single customer's volumes need dedicated resources, or where you must be able to hand a customer their data in complete isolation. It has real costs: updates to propagate, heavier onboarding, operational complexity growing linearly with customers.

Because isolation in Pwas is declared rather than hand-written, the choice can be made for business reasons instead of out of fear, and in mixed configurations — most customers shared, the few with special requirements separated — the same domain description serves both scenarios.

"Our customers have different internal roles from each other. How is that handled?"

That's the normal B2B scenario, and where the difference is felt most. Customer A has three roles, customer B wants five with its own names, customer C wants a particular field visible only to a certain responsibility.

In the traditional model every variant of this is a development request, and after ten customers permission management is the most intricate part of the product — the part nobody wants to touch.

In the declarative model roles and visibilities are configuration data, not code. That enables something SaaS products rarely offer: letting the customer define their own roles, within the limits you set, without requiring intervention from you. Your support stops being the bottleneck for every permission request.

The limit to know: the more flexibility you give, the more your product has to be able to explain to the customer's administrator what they're configuring. The hard part stops being technical and becomes experience design.

"We need to expose APIs to our customers. Does anything change?"

It changes for the better, and it's one of the less obvious benefits until you get there.

In the traditional approach, the public interface is a second product: it has its own authorisation layer, its own checks, its own risk surface, and must be kept in sync with the main application. It's also where isolation problems most often show, because it's the part most used by people who don't know internal conventions.

When permissions are declared on the domain, the exposed interface has no authorisation layer of its own: it uses the same one. A customer calling with their own credentials sees exactly what they'd see in the application, no more and no less. Exposing a new entity means declaring that it's exposed, not redesigning the checks.

Everything else a serious public interface needs — rate limiting, versioning, documentation, key management — still has to be designed, but those are real problems that aren't isolation problems.

"We're already live with our own architecture. Is changing worth it?"

It depends where it hurts, and the honest answer is often no.

If your product is stable, permissions hardly ever change and you aren't continuously adding entities, the benefit doesn't justify the work. Declared isolation delivers value in proportion to how often the model changes.

It is worth assessing in three recurring situations. When permissions have become the product's brake: every customer request about who sees what turns into development. When you've had an isolation incident, or came close, and you know the current defences are procedural. When you're about to add a channel — a public interface, a portal, an AI agent — and realise that replicating the checks on that channel is a project of its own.

Even then the approach is incremental: one domain at a time moves into the declarative model, without stopping the product. The same logic as application modernisation applies, with the same recommendation to start from a narrow scope.

quick check

Is this your case?

Probably yes

  • You're building a B2B SaaS product where customers have different internal roles.
  • Permissions have become the most fragile and feared part of your product.
  • You add entities and features frequently and each time you must repeat the checks.
  • You need to expose interfaces or portals to customers and security worries you.
  • Some customers have stricter data separation requirements than others.
  • You want customers to configure their own roles without going through your support.

Probably not

  • Your product is stable and the permission model hasn't changed in years.
  • You have one user type and no need for differentiated visibility.
  • Your main problem is infrastructure scaling, not logical isolation.
  • You're looking for an identity and access management product to bolt onto an existing system.
frequently asked

Multi-tenant SaaS: the specific questions.

How is data shared between tenants handled?
It's declared as such. A common catalogue, a reference table or a global configuration are entities with a different ownership rule: readable by all, editable only by platform roles. Because the rule is explicit, there's no ambiguity about which data is shared — which is exactly the question your first security-conscious customer will ask.
Can a user belong to several tenants?
Yes, and it's one of the scenarios to define at the start because it shapes the model. Typically it concerns consultants or partners working across several customers. The ownership rule can provide that the user sees data for the tenants they're associated with, potentially with different roles for each. It must be designed deliberately: it's also where a wrong definition of tenant costs most.
Does it handle multilingual products for different tenants?
Yes. A field can be declared translatable, and the engine automatically handles storage of language variants, reads with fallback to the default language, and nested updates on write. It works per tenant, meaning customers in different countries can have content in their own languages without you managing it by hand.
What's the performance impact of such granular checking?
Ownership and visibility conditions are resolved at runtime and translate into filters applied at source, not post-filtering in memory: the cost is comparable to a hand-written filter in the same query. Sizing is still done against your real volumes during the project, and load testing precedes go-live.
Can we give customers a trial environment?
Yes, and it's a common configuration: a trial tenant with its own data, isolated like any other. Because isolation is the base property, a demo environment doesn't require a separate installation unless you want one for other reasons, such as avoiding any contact with production data.
How long to a first product in production?
For a narrow but real functional scope — a set of entities, the roles, tenant onboarding — the order of magnitude is a few weeks from the agreed model definition. Time concentrates on product design, not on isolation infrastructure, which is traditionally what consumes most of it.

Launching a SaaS product?

We'll show you multi-tenant isolation on a working application, and how it behaves on the paths where it usually breaks.