Upgrade Guide
Upgrading a multi-tenant platform differs materially from a single-site Botble install. Every store has its own database and queue, and the queue worker holds stale code in memory if not restarted. Follow these steps exactly.
Before you upgrade
Back up everything. You cannot recover from a corrupted backup, but you can recover from an incomplete upgrade.
Back up the central database
mysqldump -u root -p saas_central > central-$(date +%Y%m%d-%H%M%S).sqlBack up every tenant database
Tenant databases follow the naming convention tenant_<id>. List them all:
mysql -u root -p -e "SHOW DATABASES LIKE 'tenant_%';" | tail -n +2 | while read db; do
mysqldump -u root -p "$db" > backup-"$db"-$(date +%Y%m%d-%H%M%S).sql
doneSave these dumps outside the server, not just in the project folder.
Back up tenant storage and the .env file
Tenant uploads live in storage/tenants/:
tar -czf storage-tenants-$(date +%Y%m%d-%H%M%S).tar.gz storage/tenants/Back up your .env file:
cp .env .env.backup-$(date +%Y%m%d-%H%M%S)Upgrade steps
1. Enable maintenance mode
php artisan downVisitors see a 503 page. The queue worker continues to run, so avoid this during heavy traffic or long-running jobs.
2. Replace the source code
# Pull from your repository or download the new version
git pull origin main
# OR
unzip ecommerce-saas-1.x.x.zipNever overwrite your .env file — the zip ships only .env.example, so unzipping over your install leaves it alone. If you do overwrite it, restore it from the backup above.
3. Install dependencies (git clones only)
The release zip ships vendor/ and the compiled assets, so a zip upgrade has nothing to install. From a git clone:
composer install --no-dev4. Migrate the central database and activate plugins
php artisan migrate --force
php artisan tenancy:activate-pluginsmigrate runs only central migrations. If it fails, roll back (see below). tenancy:activate-plugins activates any plugin the new release adds to what a store can be seeded with; plugins already active are skipped, so on most upgrades it changes nothing. It must run before step 5: a store's migrations call into plugin code, which only loads once the plugin is active platform-wide.
5. Migrate every tenant database
php artisan tenancy:migrate-tenants --pretend # see what each store would get, writes nothing
php artisan tenancy:migrate-tenants # applyThis applies the release's pending migrations to every existing store, running the same set provisioning runs, inside each store's own database. A store that fails is reported and skipped — the others still migrate — so read the summary and re-run with --tenants=<id> once you have fixed the one it names. See Artisan commands.
Not tenants:migrate
stancl/tenancy's own tenants:migrate, tenants:migrate-fresh and tenants:rollback point at a migration path this build does not have. They are refused on this platform — they print an error and touch nothing. See Artisan commands.
6. Publish theme assets
php artisan tenancy:publish-theme-assetsCopies each theme's CSS, JS and images into the shared public/themes directory. Fast, but critical — without it, storefronts have broken styling.
7. Restart the queue worker
Critical step
The queue worker holds the old code in memory. Restarting it ensures new jobs use the new code.
systemctl restart queue-workerOr, if you use Supervisor:
supervisorctl restart tenancy-queue-worker:*Wait 5 seconds and check the worker is running:
systemctl status queue-worker
# or
ps aux | grep "queue:work"If the worker fails to start, check the logs:
tail -50 storage/logs/laravel.log
sudo journalctl -u queue-worker -n 508. Verify upstream patches
The platform applies non-destructive Botble patches. The package ships a test suite that covers them, but it is not in the release zip — the build excludes tests/ and installs with composer install --no-dev, so neither vendor/bin/phpunit nor the tests are present on a customer install. (The phpunit.xml you may notice in the zip is an orphan.)
Verify the patches by hand instead — each is a small, greppable change:
php artisan tenancy:preflightPreflight asserts the conditions the patches exist to guarantee. For the patches themselves, see Upstream patches, which lists each one with the file and what to look for.
If you are working from a git clone rather than the release zip, the suite is available:
composer install # restores dev dependencies
vendor/bin/phpunit -c platform/packages/tenancy/phpunit.xml9. Run the preflight check
php artisan tenancy:preflightAmong other things, this asserts:
- Central control-plane tables exist
- Every plugin a new store can be seeded with is active platform-wide
- The configured cache store can keep two keyspaces apart
- Theme assets are published
- The queue is on a real connection, not
sync
If any check fails, fix it before going live.
10. Exit maintenance mode
php artisan upVisitors can now access the platform and all stores.
Rollback plan
If anything fails after step 4, do not continue. There is no rollback command for store databases — stancl's tenants:rollback is refused here — so the backups you took above are the rollback:
php artisan down
# restore the previous source (git reset --hard HEAD@{1}, or your backed-up files)
mysql -u root -p saas_central < central-<timestamp>.sql
# restore each store that step 5 had reached, from its backup-tenant_<id>-<timestamp>.sql
php artisan optimize:clear
php artisan upTenant user sessions are unaffected; they log back in normally.
Restart the queue worker after a rollback too (step 7) — it keeps running whichever code it booted with until it is restarted.
Timing
On a platform with:
- 10 stores: 5–10 minutes total
- 50 stores: 15–25 minutes total
- 100+ stores: 30–45 minutes total
Most of this is tenant migration time. Run upgrades during off-peak hours. The central database migration is fast (usually under 1 minute).
