Contact

ResourcesWhitepapers

Whitepaper

How should you build a multi-tenant SaaS application on Laravel?

Derick PayneDerick PayneFounder and Director

Published 16 June 2026Read 11 min

About this paper

In this paper

Fourteen sections, about 11 minutes to read.

  1. What is a multi-tenant SaaS application?
  2. When is it worth building one?
  3. Which tenancy model should you choose for a Laravel SaaS?
  4. Why did we choose a database per tenant?
  5. How does the application know which tenant is asking?
  6. Does knowing the tenant mean the user may see its data?
  7. Where does isolation leak besides the database?
  8. Should you use a Laravel tenancy package?
  9. How do you prove tenants are isolated?
  10. What about custom domains?
  11. Where should it run, and where does the data live?
  12. What do you take on after launch?
  13. FAQ
  14. What should you do next?

Build a multi-tenant SaaS application on Laravel so that every tenant request and queued job knows its tenant and stops when it does not, and every tenant file sits in tenant-scoped storage. Choose the tenancy model from how strictly you must keep tenants apart, check each user may act for that tenant, and prove the isolation with tests.

On this page
  1. What is a multi-tenant SaaS application?
  2. When is it worth building one?
  3. Which tenancy model should you choose for a Laravel SaaS?
  4. Why did we choose a database per tenant?
  5. How does the application know which tenant is asking?
  6. Does knowing the tenant mean the user may see its data?
  7. Where does isolation leak besides the database?
  8. Should you use a Laravel tenancy package?
  9. How do you prove tenants are isolated?
  10. What about custom domains?
  11. Where should it run, and where does the data live?
  12. What do you take on after launch?
  13. FAQ
  14. What should you do next?

I have worked in IT and development since 1998. This guide draws on two products Rizonetech is building on Laravel, SecureBin and MailMark. Neither is released yet, their designs may still change, and parts described here are tested in development, not yet in production. Reviewed 12 October 2026 by Derick Payne, with the published facts about Laravel, hosting and POPIA read that day.

What is a multi-tenant SaaS application?

A multi-tenant application is one codebase that serves many customers, called tenants, and keeps each tenant’s data apart. A tenant can be a client company, a branch or a franchise. Each signs in to what looks like its own system, but you run, update and back up one application.

When is it worth building one?

Build one when the software is your product, or when many clients, branches or franchises need the same system with their data kept apart, and no product does it on terms you can accept. Our guide to when a business needs custom software covers that decision.

Which tenancy model should you choose for a Laravel SaaS?

There are three common models. Microsoft’s guidance on tenancy models treats isolation as “a spectrum”, not a yes or no.

ModelHow tenants are kept apartRunning costMain risk
Shared databaseA tenant ID on every row, applied to every queryUsually the cheapest to operateIf only the application filters rows, one unscoped query can show another tenant’s data
Schema per tenantA separate schema inside one shared database, as PostgreSQL offersDepends on the database and the number of tenantsMigrations run per schema, and in MySQL a schema is simply a database
Database per tenantA separate database, chosen for each request or jobAdds a database to create, migrate and back up per tenantCode that picks the wrong connection serves the wrong tenant

With a shared database, Microsoft says you “typically rely on your application code and a tenant identifier” to keep data apart. Some databases can enforce the filter themselves: PostgreSQL’s row security policies restrict which rows a query returns. In PostgreSQL a database contains named schemas, which makes schema per tenant a real third option, while in MySQL CREATE SCHEMA is a synonym for CREATE DATABASE. A database per tenant moves the boundary into the infrastructure, but its cost “can be higher than shared hosting models”, because you provision data resources for each tenant. Separate databases can still share one database server, so the real cost depends on your hosting and workload. You also have to automate creating and migrating them.

No model makes a leak impossible. Separate databases strengthen isolation, but the code that picks the connection, the credentials it uses and the access rules still need testing. Per-tenant backup, restore and deletion also need procedures you design and test, not ones you assume.

Why did we choose a database per tenant?

SecureBin and MailMark both use one codebase with a separate database for each tenant. We chose it for two reasons:

  • The data is sensitive. SecureBin is for sharing sensitive data, and MailMark holds staff directories, email signature content and sign-in settings. A boundary in the infrastructure is easier to reason about than a filter that every query must remember.
  • A tenant can be handled on its own. A database per tenant gives backup, export and offboarding a natural unit, once those procedures are built and tested.

The two products draw the line between central and tenant data differently. SecureBin’s central “landlord” database holds the tenant register, domains, plans, provisioning steps and an audit log of landlord actions, while each tenant database holds that tenant’s users, records and settings. MailMark keeps sign-in identities, sessions and delegated access in its central database, and each workspace’s business records in the workspace database. A central identity is not enough there: the user still needs permission inside that workspace. In MailMark, the register stores a reference to each tenant database’s credentials in a vault, not the passwords themselves.

The price is operational. Both use one set of tenant migrations, but a migration can fail for one tenant and not another, so you need to see each tenant’s migration status and retry the failures. MailMark’s migration command takes a central lock, records each tenant’s failure separately and can be run again safely.

How does the application know which tenant is asking?

It reads the hostname. In SecureBin, a request to a tenant’s subdomain resolves to a tenant only when that exact hostname is an active domain of an active tenant in the landlord database. Anything else is treated as unknown and answers 404. It never falls through to a default tenant.

Some names never resolve as tenants at all. SecureBin reserves subdomains such as www, admin, api, status and support, so nobody can sign up as “admin” and catch traffic meant for something else. Marketing pages and the landlord console run on their own hostnames.

Failing closed is the first rule: if the application cannot tell which tenant a request belongs to, it should stop, not guess.

Does knowing the tenant mean the user may see its data?

No. The hostname or workspace reference only says which tenant a request is about, and anyone can type a valid hostname or copy a reference. After the tenant is known, check that the signed-in user, or the integration’s token, belongs to that tenant and has permission for the action. A session or token from tenant A must be refused on tenant B’s hostname, object IDs and file paths, even when those all exist.

Where does isolation leak besides the database?

Switching the database connection is the start, not the end. These are the places we found that also need the tenant:

  • The cache. SecureBin switches the cache key prefix to the tenant on every switch, and tests it with the database cache store. A prefix only isolates stores that honour it, so test each cache store you deploy.
  • Queued jobs. A background worker has no hostname to read. MailMark refuses to run a tenant job that does not carry its workspace key, binds that tenant for the job, and clears the connection when the job ends. It does this in Laravel’s job middleware, which wraps custom logic around each queued job.
  • Long-running processes. A queue worker stays running between jobs, and Laravel Octane “boots your application once, keeps it in memory” between requests. If a connection or a stored setting is not reset on each switch, the next request can inherit the previous tenant. Both products purge the tenant connection on every switch.
  • Scheduled tasks. A scheduled command has no hostname either, so it must choose its tenants itself, bind each one in turn and restore the connection afterwards, even when one tenant fails. SecureBin’s scheduled health check is tested to run for active tenants only, skip a suspended one and leave the default connection restored. If a task must not overlap, key its lock by tenant.
  • Files. MailMark prefixes storage paths with the workspace, for media, banners and signature images.
  • Webhooks and callbacks. Sign-in callbacks, provider webhooks and tracking links arrive without a tenant hostname, so MailMark requires an explicit workspace reference in the payload or signed token. It never infers the tenant from the previous request.
  • Encryption keys. SecureBin resolves a separate share encryption key reference for each tenant.

Should you use a Laravel tenancy package?

Usually it is worth looking first. Tenancy for Laravel (stancl/tenancy) can identify tenants by domain or subdomain, focuses on a database per tenant, and switches the database connection, cache, files and queues to the tenant once it is identified. Spatie’s laravel-multitenancy works with one database or several, and switches the tenant database through a task you configure.

For SecureBin we chose a small resolver of our own, and recorded why at the time. The tenancy model, the landlord tables and the deployment were still being settled, and a package would have brought its own tenant model, events and configuration around every job, scheduled command and cache. We kept the host rules, database naming and fail-closed behaviour in our own code, and wrote down that we would look at a package again once provisioning, queues and database permissions on the hosting were proven. MailMark also uses its own tenancy code, without a package.

That is a judgement for a specific product, not a rule. Whichever you choose, check that it supports your Laravel version, covers every boundary in this guide, and passes your own isolation tests.

How do you prove tenants are isolated?

With tests that try to break it. Microsoft’s tenancy guidance says to test your solution “to verify that one tenant’s data isn’t accidentally leaked to another”.

SecureBin has a test that creates two tenants, each with one user, then requests the same page for the first tenant and then for the second, back to back. Each response must show only its own tenant’s user. That catches the bug that matters most with a database per tenant: a connection left behind from the previous request.

Other tests in the two products cover the cache, email, scheduled tasks, queued jobs and matrices of selected tenant-owned models. A matrix is only as complete as its list, so check it against every model that holds tenant data. Add the authorization cases too: tenant A’s session against tenant B’s pages, records and files. When you commission a multi-tenant build, ask to see these tests and run them.

What about custom domains?

When a tenant brings its own domain, two things must hold: the tenant proves it controls the domain before you route it, and no other tenant can claim the same name. MailMark has a development test of that order: a DNS TXT check before a certificate is requested, and a second workspace refused when it tries to claim a domain another workspace holds. The test uses simulated DNS and certificate results; live DNS and certificate issuance are not yet proven.

The reverse risk is a DNS record left pointing at a resource that no longer exists. Microsoft describes this for Azure as subdomain takeover: a “dangling DNS” record can be taken over when someone else is assigned the resource it points to. Remove a departed tenant’s domain from routing, and ask the tenant to remove its DNS record, as part of offboarding.

Where should it run, and where does the data live?

Choose hosting by the regions and services available today, not by a list from a few years ago. As read on 12 October 2026:

If personal information leaves South Africa, the transfer needs a valid basis under POPIA section 72, such as a recipient bound by law or an agreement giving adequate protection, or the data subject’s consent. Count every copy: the databases, files, backups and logs, and every service that receives the data. Check the specific transfer with your privacy or legal adviser.

What do you take on after launch?

More than with a single-tenant system:

  • Migrations across every tenant, on every deploy, with a way to see and retry a tenant that failed.
  • Backups you have restored. MailMark’s development workflow refuses to activate a workspace until its backup settings are marked verified with at least two days’ retention. That check runs against simulated provider results today, and real backup verification and restore drills are still to come. Neither replaces restoring a tenant from backup and checking the result.
  • Provisioning and offboarding as code. Creating a tenant, suspending it and removing its data should be commands with a record, not manual steps.
  • Framework upgrades. Laravel’s support policy gives each major version 18 months of bug fixes and two years of security fixes, so plan upgrades before security support ends.

FAQ

Is a database per tenant always safer?

No. It moves the boundary into the infrastructure, but a bug in the code that picks the connection, or a missing permission check, can still expose the wrong tenant. Test it either way.

Can I start with a shared database and move later?

Yes, but moving data and changing every query later is expensive. Decide early, from how sensitive the data is and how many tenants you expect.

Does Laravel support multi-tenancy out of the box?

Laravel gives you the parts: database connections, middleware, queues, job middleware and cache prefixes. Tenancy itself comes from a package or your own code.

How many tenants can one application serve?

It depends on the model and the hosting. A database per tenant adds a database, a migration run and a backup for each tenant, so plan the operations before the numbers grow.

What should you do next?

See where your systems stand with the free IT health check. If your business needs one system for many clients or branches, see how Rizonetech scopes and builds custom software with Laravel. For the cloud side, read our Azure migration and governance whitepaper.

Published 16 June 2026. Last updated 12 October 2026.

Map one workflow with us

Tell us which job is typed in twice, or which tools do not talk to each other. We'll tell you plainly what it takes, before any work starts.