About

Building a multi-tenant SaaS with Filament PHP — what worked, what didn't, and why I'd do it again

Filament gets you to a working admin panel fast. Building a product on top of it is a different, more interesting problem.

Opening

When I started building BookWise — a CMS, CRM and scheduling platform for small businesses — I had a decision to make early: build the admin interface from scratch, or find something that could handle the boilerplate while I focused on the actual product.

I'd used Filament PHP before in my day job and knew it well enough to have opinions about it. So I reached for it again, and spent the next several months discovering exactly where that decision paid off and where it made things more complicated than I expected.

This is that story.


What Filament Actually Is

If you haven't used it: Filament is an admin panel framework for Laravel. Out of the box it gives you a full CRUD interface, form builder, table builder, filters, actions, notifications, and a design system — all of it built on the TALL stack (Livewire, Alpine, Tailwind).

The pitch is that you can go from a database schema to a fully functional admin interface in a fraction of the time it would take to build one manually. That pitch is largely true. The more interesting question is what happens when you're not building a simple admin panel — when you're building a product that needs to feel like a product rather than a backend tool someone forgot to style.

That's the territory BookWise occupies, and it's where things get interesting.


Why Filament Made Sense for BookWise

BookWise has a lot of moving parts. Each tenant organisation has its own clients, appointments, services, staff members, and calendar configuration. The admin side of that — the interface where a business owner manages all of this — is essentially a series of interconnected CRUD interfaces with business logic woven through them.

Building all of that from scratch would have taken months. Filament gave me the scaffolding in days.

The form builder in particular is genuinely excellent. Defining a complex form — nested relationships, conditional fields, repeaters, file uploads — is a matter of composing PHP objects rather than writing HTML. The result is clean, consistent, and testable. For the appointment booking form alone, which has conditional availability logic, service selection, staff assignment, and Google Calendar sync, having Filament's form abstractions to work with saved an enormous amount of time.

The table builder is similarly strong. Filtering, sorting, searching, bulk actions — all of it is handled at the framework level. I define what I want, Filament works out how to render and wire it up.


The Multi-Tenancy Problem

Here's where it gets more involved.

Filament is not a multi-tenant framework out of the box. It's designed around a single admin panel for a single organisation — typically you, the developer, managing your own application. Turning it into something where each tenant has their own isolated panel, their own data, their own users, and their own configuration required deliberate architectural work.

The approach I took was using Filament's panel system — which lets you define multiple distinct admin panels within a single Laravel application — combined with a tenant resolution layer that identifies which organisation a user belongs to and scopes every query accordingly.

In practice this means every resource, every query, every action in the panel is scoped to the current tenant automatically. A law firm in Santiago sees only their clients. A physio clinic in Melbourne sees only theirs. The data isolation happens at the model layer through global scopes, which means I can't accidentally serve one tenant's data to another.

Getting that right took more iteration than I expected. Filament makes a lot of assumptions about being the only panel in town, and unpicking those assumptions to support proper multi-tenancy requires reading the framework internals carefully and being willing to extend things it didn't explicitly design for extension.


The Public Booking Interface

BookWise isn't just an admin panel — it has a public-facing booking page that clients interact with. This is where Filament's role ends and the TALL stack takes over directly.

The public booking flow is built in plain Livewire components, styled with Tailwind, without Filament's design system. This was deliberate: the booking page needs to feel like the business's own interface, not a generic admin tool. Tenants can configure their own colours, logo, and services. The experience should feel branded and lightweight, not like they've accidentally wandered into a backend dashboard.

That separation — Filament for the management side, raw TALL for the customer-facing side — ended up being a clean architectural decision. Each part of the application uses the right tool for its context.


Google Calendar Sync

One of BookWise's key features is two-way Google Calendar sync — appointments created in BookWise appear in the business owner's Google Calendar, and changes made in Google Calendar reflect back in BookWise.

Filament didn't help or hinder this particularly — it's a pure Laravel concern handled in the service layer. But it's worth mentioning because it's one of those features that sounds simple and is not. OAuth flows, webhook handling, conflict resolution, timezone management — each one is a small project in itself.

The integration lives entirely outside Filament in a dedicated service class. Filament just provides the UI controls for connecting and managing the calendar. That clean separation made testing and debugging significantly easier.


What I'd Do Differently

A few honest things I'd revisit:

The multi-tenancy architecture worked, but I arrived at it through iteration rather than design. If I were starting again I'd make the tenancy layer a first-class architectural decision from day one rather than something I retrofitted onto a Filament foundation. The framework can support it, but it rewards planning.

I also underestimated how much time the public-facing side would take relative to the admin panel. Filament made the management interface fast to build. The customer-facing booking flow — which is what end users actually see — took just as long as everything else. The lesson: don't let the speed of the admin scaffold create a false sense of overall progress.


The Honest Summary

Filament PHP is genuinely one of the best tools available in the Laravel ecosystem for building admin interfaces fast. For BookWise it meant I could focus on the product decisions — what features matter, how the data model should work, how tenants should interact with their own data — rather than spending months building form components and table filters from scratch.

The multi-tenancy work was real effort and required going off the beaten path. But the framework was extensible enough to support it without fighting me too badly.

If you're building a Laravel SaaS that needs a management interface, and you're willing to invest time upfront in the tenancy architecture, Filament is worth serious consideration.