Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Multisite Laravel Package

appstract/laravel-multisite

appstract/laravel-multisite is a Laravel package for serving multiple websites from one codebase. It resolves the current site by domain, adds site-aware models and middleware, and helps keep content and configuration separated across domains.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install and publish. composer require appstract/laravel-multisite, then publish the provider assets (php artisan vendor:publish --provider="Appstract\Multisite\MultisiteServiceProvider"). You get a config/multisite.php and, depending on version, a middleware entry to register in app/Http/Kernel.php.
  2. Look first at config/multisite.php. Site registration lives there: a sites array keyed by a slug, each with at least a domain (or hostname) and optional per-site paths for config, views, routes, and database. This file is the package — everything else is resolution and swapping.
  3. Add the middleware. Put the package middleware at the top of the web group (before StartSession, Authenticate, and SubstituteBindings) so the active site is known before sessions, auth, or routing read config. Verify in Kernel.php; if the package auto-registers, confirm via php artisan route:list -v.
  4. Register two sites and test the hostname switch. Point site-a.test and site-b.test at the same vhost (Valet/Homestead hosts file). Hit each domain; you should see the different view/route/config output. That two-site smoke test is your first use case and immediately tells you whether path swapping works before you invest in real content.
  5. Inspect the resolved site at runtime. Dump the active site object/helper (e.g. the package facade or helper that returns the current site) in a route or AppServiceProvider::boot() to confirm domain, loaded config, and DB connection. This is faster than reasoning from the config file.

Implementation Patterns

  • Config-driven site registry. Treat config/multisite.php as the source of truth and keep each site's overrides in dedicated directories (sites/{slug}/config, sites/{slug}/routes, resources/views/{slug}). This mirrors the package's "drop-in" design and avoids a schema migration just to add a domain.
  • Per-site routes. Keep a base routes/web.php for shared endpoints and load sites/{slug}/routes/web.php for site-specific ones. Wrap site routes in per-site middleware/prefixes if you need different auth guards.
  • Per-site database. Set the database connection name per site in config and reference it via config('database.default') after detection — models should never hardcode a connection. Use ->on(site()->connection) or resolve the connection from config so tests can swap it.
  • Config overrides as merge, not replace. The pattern that scales is: load the framework default, then array_merge the site's config values on top. Fully replacing config per site quietly breaks mail, cache, and filesystem drivers.
  • Site-aware services. For anything host-dependent (asset URLs, mail from-address, Stripe keys, cache prefix), read from the resolved site config rather than env(). env() is cached at boot and won't vary per request.
  • Testing. Use $this->get('http://site-b.test/...') (or set the Host header / SERVER_NAME) so Laravel's test client exercises the real detection path. Add one feature test per site hitting the home route.

Gotchas and Tips

  • Age and Laravel version. Last release was January 2018, so this targets Laravel 5.x. On Laravel 9+/10+/11 you should expect to fork or vendor the package: service provider registration, middleware kernel shape, and container binding have all changed. Budget for a fork before committing.
  • Route and config caching. php artisan route:cache and config:cache run without an HTTP host, so site detection has nothing to resolve. Either disable caching for the multisite middleware or add a "current site" override the console can set.
  • Console and queue workers have no hostname. Any artisan command, scheduled job, or queued listener will resolve no site (or a fallback). Pass the site slug explicitly into jobs (new SyncJob($siteSlug)) and call the package's site-switch API at the top of handle(); otherwise multi-tenant jobs silently write to the wrong database.
  • Middleware order is the whole ballgame. If detection runs after StartSession, you'll get the default site's cookie domain and database, and debugging is miserable. Put it first, and log the resolved host + slug during development.
  • Storage and cache collisions. storage/framework/views and cache prefixes are shared unless you namespace them per site (e.g. config(['cache.prefix' => site()->slug])). Two sites with the same view name but different content will render the wrong compiled Blade.
  • Missing site = silent 404 or default site. Decide explicitly what happens on an unknown host. A loud 404 (or a 301 to a canonical domain) is easier to debug than falling through to the first site in the array.
  • URL generation. asset() and url() depend on the current request root; if you generate links to another site's domain you must override the root yourself, since the package only resolves incoming hosts.
  • Extension point. Rather than patching the package, wrap detection in your own middleware that calls the package's resolver, then applies additional per-site bootstrapping (tenant-aware storage, feature flags). That keeps upgrades/fork merges to a single file.
  • Local dev. *.test domains plus a single vhost with ServerAlias is the least painful setup; remember to clear config:cache after adding a new site to the array, or the new domain won't exist as far as the package is concerned.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
adachsoft/php-code-style