Skip to content

Laravel multisite: several sites in one application, a database per site ​

An agency keeps eleven client sites on the same stack. A publisher runs a magazine, its events site and a shop. A school has a site per campus. Each wants its own domain, its own content and its own administrator, and nobody wants eleven deploys, eleven update rounds and eleven sets of credentials to look after.

WordPress answers this with Multisite: one install, a network of sites, each with its own tables, users, theme and plugins switched on. On Laravel the usual answers are a multi-tenancy package, which is built for a SaaS and its sign-up flow, or a copy of the application per site, which is the eleven deploys again.

kitloom/multisite is the WordPress answer on Laravel: one application, one deploy, a site per domain — with its own database, content, users, theme and modules, managed from the main site's admin.

How a site is chosen ​

The site your .env describes is the main site. The others are rows of a sites table in its database. A row names the hosts the site answers — the first is its address, the others redirect to it — and where its data is:

  • A SQLite file of its own, in storage/sites/<name>/. Nothing to set up; enough for a small site on a server with a disk.
  • A MySQL database of its own: a database and a user you made on the server.
  • The main database, with a table prefix of its own — the way a WordPress network keeps its sites: shop_posts beside wp_posts.

On every request the host picks the row, before anything else runs. The application then points its database connection, its uploads folder, its address and its cache namespace at the site and boots as it always does: the active theme, the switched-on modules and every setting come from that database. A site cannot see its neighbours; the main site is the only place the network is managed from.

Nothing of the application is copied per site. The code, the installed modules and themes, the built assets, Redis and the queue are shared; what a site has of its own is its database and its files.

Adding a site ​

Sites → New Site in Filament, or Sites → Create Site in Nova: the name, the hosts, the database. Leave Set the database up now ticked and name the administrator: the migrations run, WordPress's options and roles are written, the administrator is made with their role, and the password is shown once. The site answers as soon as the DNS and the web server point the domain at the application.

The same from the console:

bash
php artisan multisite:create shop shop.example.com www.shop.example.com [email protected]

Every artisan command runs on a site with --site=<name> — migrate --site=shop, queue:work --site=shop — and multisite:run all "migrate --force" runs one on the main site and every site, a process each. One cron line, schedule:run on the main site, runs every site's schedule; queued jobs carry the site that queued them and the worker switches onto it.

Watch it ​

A second site added from the admin: its domain, its database, its administrator — answering a minute later

What to know before ​

  • Users are per site. An account on one site is not an account on another. A WordPress network shares users across its sites; a network moved here gets its users copied into each site.
  • The main site's migrations are what a new site gets. Keep every module on while sites are made, or run migrate --site=<name> after switching one on.
  • Laravel Nova checks its licence against the request's domain. Ask Laravel about a licence for the network's domains before running Nova sites this way. Filament has no such check.
  • Deleting a site takes it off the list. Its database and files stay where they are; Pause keeps it on the list and shows its visitors a page saying it is paused.

Try it ​

Open a sandbox in one click, with no sign-up: Filament or Nova. Every detail of the module is in the Multisite guide.

Last updated:

kitloom — modules and themes for Laravel.
Contact · Pricing · Services · License · Refunds · Privacy · Community · YouTube · [email protected]