Quickstart
From an installed plugin to your first tenant running on its own database — about five minutes. You'll create a user, walk through the onboarding wizard, watch provisioning run, and land in the tenant's panel.
Note
This guide assumes you've finished Installation in subdomain mode with myapp.test as your central domain and a queue worker running. Path mode works the same way; only the URLs differ.
Want to see the finished result first? Open the hosted demo — the login form comes pre-filled — or clone the demo repository, a deliberately small app built by following this guide.
1. Create a user and sign in
php artisan make:filament-user
Visit http://myapp.test/admin/login and sign in. Login always happens on the central domain — one account, every workspace.
2. Create your first tenant
Your user belongs to no tenants yet, so Filament sends you straight to the Create organization wizard (also reachable any time at /admin/new).
- Enter a name — Acme Inc. — and the URL slug (
acme) fills in as you leave the field. - Confirm on the second step.
The tenant row, its acme.myapp.test domain, and your ownership record are committed to the central database in one transaction, and the provisioning pipeline is dispatched to your queue.
3. Watch it provision
You land on a status page that polls the tenant while your worker runs CreateDatabase → MigrateDatabase → MarkTenantReady (plus SeedDatabase, if you've configured a tenant seeder). It usually takes a few seconds.
| What you see | What it means |
|---|---|
| Spinner, then a redirect | Done — the tenant is ready and you're sent into its panel. |
| "Taking longer than usual" after 90 s | The worker is busy — or not running. Check php artisan queue:work. |
| A failure state | A job threw. The usual suspect is a broken tenant migration; check the worker output, fix it, then php artisan tenants:retry-provisioning acme. |
A tenant is never left half-built: until it's ready, every visit is routed back to this page.
4. You're in
You're now at http://acme.myapp.test/admin — Acme's own panel, backed by Acme's own database. The switcher in the sidebar lists your organizations; /admin/new creates more.
Build resources exactly as you would in a single-tenant app. No tenant_id columns, no global scopes — every query in tenant context automatically hits that tenant's database.
5. Add a tenant table
Everything in database/migrations/tenant/ runs against each tenant database. Try it:
php artisan make:migration create_projects_table --path=database/migrations/tenant
php artisan make:filament-resource Project --generate
Create a second tenant through the wizard: each one gets its own projects table, and the resource shows only that tenant's rows. (For tenants that already exist, run php artisan tenants:migrate to apply the new migration.)
Where to next
- How it works — what lives in the central vs. tenant database, and how requests find their tenant.
- Configuration — every option, with the fluent
TenancyPluginAPI. - Custom domains — let tenants serve their panel from
app.their-company.comwith one line:TenancyPlugin::make()->customDomains(). - Horizontal scaling — spread tenant databases across servers:
TenancyPlugin::make()->databasePool(['tenant_pool_1', 'tenant_pool_2']). - Production checklist — DNS, TLS, queue workers, config caching, backups.