DEV Community

Cover image for Deploying a Laravel + Livewire SaaS with Multi-Tenancy on Deploynix
Deploynix
Deploynix

Posted on • Originally published at deploynix.io

Deploying a Laravel + Livewire SaaS with Multi-Tenancy on Deploynix

Multi-tenant SaaS applications are among the most architecturally complex Laravel projects to deploy. You are not just running one application — you are running one application that behaves differently for every tenant, often with separate databases, isolated data, and tenant-specific configurations.

Add Livewire into the mix — with its server-rendered components, persistent connections, and file upload handling — and the deployment requirements become even more specific. The infrastructure needs to handle tenant resolution, database switching, queue isolation, and Livewire's stateful component lifecycle, all without mixing tenant data or degrading performance.

This guide walks through deploying a Laravel + Livewire multi-tenant SaaS application on Deploynix, using Stancl/Tenancy as the tenancy package. Stancl/Tenancy is the most widely adopted multi-tenancy package for Laravel, and its database-per-tenant architecture is the most common pattern for SaaS applications that need strong data isolation.

Understanding the Architecture

Before touching infrastructure, let us clarify what we are deploying:

The Application Stack

  • Laravel as the framework.
  • Livewire for interactive UI components without writing separate JavaScript.
  • Stancl/Tenancy for multi-tenancy, using the database-per-tenant approach.
  • MySQL or PostgreSQL as the database (one central database plus one per tenant).
  • Valkey for cache, sessions, and queues.

How Stancl/Tenancy Works

Stancl/Tenancy identifies tenants through domain or subdomain resolution. When a request arrives at acme.yourapp.com, the tenancy middleware looks up the tenant associated with acme, switches the database connection to that tenant's database, and the rest of the request lifecycle operates within that tenant's context.

The central database stores tenant metadata: which domains map to which tenants, subscription status, and plan information. Each tenant has its own database containing application data: users, projects, invoices, and everything else.

Why Database-Per-Tenant

Database-per-tenant provides the strongest data isolation:

  • Tenant data cannot accidentally leak across tenants through query mistakes.
  • You can back up, restore, and migrate individual tenants independently.
  • Performance issues in one tenant's database do not affect others.
  • Compliance requirements (GDPR data deletion, data residency) are easier to satisfy.

The tradeoff is operational complexity — managing hundreds or thousands of databases requires automation. Deploynix and Stancl/Tenancy together handle this automation.

Step 1: Provision the Server

For a multi-tenant SaaS, server sizing matters more than for a single-tenant application. Each tenant database consumes memory when active, and the total connection count across all tenants can be significant.

Starting configuration:

  • Server type: App Server on Deploynix.
  • Provider: DigitalOcean, Vultr, Hetzner, Linode, AWS, or Custom.
  • Specs: 4 vCPUs, 8GB RAM minimum. Multi-tenancy is memory-hungry due to multiple database connections.
  • Database: MySQL or PostgreSQL (match what you use in development).

Provision the server through the Deploynix dashboard. The platform handles PHP, Nginx, database, and Valkey installation.

Database Configuration for Multi-Tenancy

After provisioning, you need to ensure your database server allows the application to create new databases dynamically. Stancl/Tenancy creates a new database for each tenant when they sign up.

The database user Deploynix creates for your application needs CREATE DATABASE privileges. You can verify and adjust this through the Deploynix database management panel or via the web terminal:

GRANT ALL PRIVILEGES ON *.* TO 'your_user'@'localhost' WITH GRANT OPTION;
FLUSH PRIVILEGES;
Enter fullscreen mode Exit fullscreen mode

This grants the application user permission to create and manage tenant databases. In a multi-server setup where the database runs on a dedicated server, adjust the host accordingly.

Step 2: Configure the Site

Create a site in Deploynix for your SaaS application. For multi-tenant applications with subdomain-based tenancy, you need to configure a wildcard domain.

Domain setup:

  • Primary domain: yourapp.com (for the central/marketing site).
  • Wildcard: *.yourapp.com (for tenant subdomains).

In your DNS provider, create:

  • An A record for yourapp.com pointing to your server IP.
  • A wildcard A record for *.yourapp.com pointing to the same server IP.

In Deploynix, configure your Nginx site to handle both the primary domain and the wildcard. Deploynix's site configuration supports wildcard domains.

SSL for Wildcard Domains

Standard Let's Encrypt certificates do not cover wildcard domains. You have two options:

Option 1: DNS-validated wildcard certificate. Deploynix supports DNS validation for SSL certificates through Cloudflare, DigitalOcean, AWS Route 53, and Vultr as DNS providers. This allows issuing a wildcard certificate for *.yourapp.com.

Option 2: Per-tenant certificates. For custom domains (when tenants bring their own domain instead of using a subdomain), Deploynix can issue individual Let's Encrypt certificates for each domain.

For subdomain-based tenancy, the wildcard certificate is the right approach. Configure it once, and every tenant subdomain is automatically covered.

Step 3: Environment Variables

Set your environment variables in the Deploynix dashboard:

APP_NAME="Your SaaS Name"
APP_ENV=production
APP_DEBUG=false
APP_URL=https://yourapp.com

# Central database
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=central
DB_USERNAME=your_user
DB_PASSWORD=your_secure_password

# Tenancy configuration
TENANCY_DATABASE_PREFIX=tenant_
TENANCY_DATABASE_SUFFIX=

# Cache and sessions
CACHE_STORE=redis
SESSION_DRIVER=redis
QUEUE_CONNECTION=redis

# Redis with prefix isolation
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
REDIS_PREFIX=yourapp_

# Livewire
LIVEWIRE_ASSET_URL=https://yourapp.com
Enter fullscreen mode Exit fullscreen mode

The TENANCY_DATABASE_PREFIX ensures tenant databases are named predictably: tenant_acme, tenant_globex, etc. This makes database management, backup, and debugging straightforward.

Redis Prefix Isolation

In a multi-tenant application, cache keys and session data must be isolated between tenants. Stancl/Tenancy handles this by prefixing cache and session keys with the tenant ID. Ensure your config/tenancy.php is configured to use tenant-aware cache and Redis drivers.

Your REDIS_PREFIX in .env provides application-level isolation (separating your app from any other application using the same Redis instance), while Stancl/Tenancy adds tenant-level isolation on top.

Step 4: Deploy Script

Multi-tenant deployments have an additional consideration: you need to run migrations for both the central database and all tenant databases.

Configure your Deploynix deploy script:

Install dependencies:

composer install --no-dev --no-interaction --prefer-dist --optimize-autoloader
npm ci --no-audit --no-fund
Enter fullscreen mode Exit fullscreen mode

Build frontend assets:

npm run build
Enter fullscreen mode Exit fullscreen mode

Run central migrations:

php artisan migrate --force --no-interaction
Enter fullscreen mode Exit fullscreen mode

Run tenant migrations:

php artisan tenants:migrate --force --no-interaction
Enter fullscreen mode Exit fullscreen mode

Optimize and restart:

php artisan optimize
php artisan queue:restart
Enter fullscreen mode Exit fullscreen mode

The tenants:migrate command iterates through all tenants and runs pending migrations on each tenant's database. For applications with many tenants, this step can take several minutes. As your tenant count grows, you may want to run tenant migrations asynchronously through a queued job rather than blocking the deployment.

Handling Large Tenant Counts

When you have hundreds or thousands of tenants, running tenants:migrate synchronously during deployment becomes impractical. Instead, dispatch tenant migrations as background jobs:

# In deploy script, only run central migrations
php artisan migrate --force --no-interaction
php artisan optimize

# Dispatch tenant migrations as background jobs
php artisan tenants:migrate --queue --force --no-interaction
Enter fullscreen mode Exit fullscreen mode

This approach runs central migrations immediately (they are fast — it is one database) and queues tenant migrations for background processing. Your deployment completes quickly, and tenant migrations run in parallel through your queue workers.

Step 5: Queue Workers — Tenant-Aware Configuration

Queue workers in a multi-tenant application must be tenant-aware. When a job is dispatched within a tenant's context, it must execute within that same context. Stancl/Tenancy handles this by serializing the tenant ID with the job payload and initializing the tenant context when the worker picks up the job.

Configure queue worker daemons in Deploynix:

Primary worker:

php artisan queue:work redis --queue=high,default,low --tries=3 --timeout=90
Enter fullscreen mode Exit fullscreen mode

Tenant-specific worker (optional):

php artisan queue:work redis --queue=tenant --tries=3 --timeout=120
Enter fullscreen mode Exit fullscreen mode

Queue Isolation Considerations

By default, all tenants share the same queue. Jobs from Tenant A and Tenant B sit in the same Redis list and are processed by the same workers. This is fine for most applications.

However, if one tenant generates a massive volume of jobs (a bulk import, a large email campaign), it can starve other tenants' jobs. To prevent this:

Option 1: Tenant-prefixed queues. Dispatch each tenant's jobs to a tenant-specific queue (tenant_acme_default, tenant_globex_default). Workers process queues round-robin, ensuring fair scheduling. This requires more complex worker configuration.

Option 2: Priority queues. Use Laravel's priority queue feature with multiple queue names. Critical jobs (payment processing, authentication) go to the high queue, while bulk operations go to low. Workers process high first.

Option 3: Dedicated worker server. If queue volume is significant, provision a dedicated worker server on Deploynix. This isolates queue processing from web request handling, ensuring that heavy background processing does not affect your application's response times.

For most SaaS applications in their early to mid stages, shared queues with priority separation are sufficient. Move to dedicated workers when your job volume justifies it.

Step 6: Livewire-Specific Considerations

Livewire adds specific deployment considerations for multi-tenant applications:

Asset Publishing

Livewire serves its JavaScript assets from a published location. Ensure the Livewire assets are published during deployment:

php artisan livewire:publish --assets
Enter fullscreen mode Exit fullscreen mode

Add this to your deploy script after npm run build. This ensures the Livewire JavaScript runtime matches the server-side version.

File Uploads

Livewire's file upload feature uses temporary storage on the server. In a multi-tenant context, ensure temporary uploads are isolated per tenant or use a shared temporary directory that is cleaned regularly.

If tenants upload files that are stored permanently, use a tenant-aware filesystem configuration. Stancl/Tenancy can prefix storage paths with the tenant ID:

// config/tenancy.php - filesystem suffixing
'suffix_base' => 'tenant_',
Enter fullscreen mode Exit fullscreen mode

This ensures Tenant A's uploads go to storage/tenant_a/ and Tenant B's to storage/tenant_b/, preventing data leakage.

Component Caching

Livewire components are resolved and rendered on the server. In a multi-tenant application, ensure that any component-level caching respects tenant boundaries. Stancl/Tenancy's cache prefix handling covers this when you use Laravel's cache system, but be cautious with any custom caching in your Livewire components.

Step 7: Database Backups

Multi-tenant backups are more complex than single-database backups because you have multiple databases to protect.

Central Database

Configure a backup for the central database through Deploynix's backup management. This database contains your tenant registry, billing information, and platform configuration. Back it up at least daily.

Tenant Databases

For tenant databases, you have two approaches:

Approach 1: Individual backups. Configure Deploynix backups for each tenant database. This gives you per-tenant restore capability but requires managing many backup configurations.

Approach 2: Full MySQL dump. Back up all databases on the server in a single operation. This is simpler to manage but means restoring a single tenant requires extracting their database from the full dump.

For most SaaS applications, the full dump approach with daily backups to S3, DigitalOcean Spaces, or Wasabi is practical. As your tenant count grows and data isolation requirements become stricter, per-tenant backups provide more granularity.

Store backups on external storage (AWS S3, DigitalOcean Spaces, Wasabi, or custom S3-compatible) — never only on the server itself.

Step 8: Monitoring and Scaling

Monitoring Multi-Tenant Performance

Deploynix's server monitoring shows overall CPU, memory, and disk usage. For multi-tenant applications, also monitor:

  • Database connection count. Each active tenant context uses a database connection. If connections approach your MySQL max_connections limit (typically 150 by default), either increase the limit or optimize connection handling.
  • Disk space per tenant. Tenant databases grow independently. A single tenant with large data volumes can consume disproportionate disk space.
  • Queue depth. Monitor queue length to detect tenant-generated job backlogs.

Scaling Strategy

Multi-tenant SaaS applications on Deploynix scale in predictable stages:

Stage 1: Single app server (1 to 100 tenants). Everything runs on one server. Good enough for launch and early traction.

Stage 2: Separate database server (100 to 500 tenants). Offload database processing to a dedicated database server on Deploynix. The app server handles web requests and queue processing.

Stage 3: Add worker server (500+ tenants or high job volume). Dedicate a server to queue processing. The app server handles only web requests.

Stage 4: Load-balanced web servers (high traffic). Add multiple web servers behind a Deploynix load balancer. Sessions use Valkey (shared across servers), and the database and cache servers are separate.

Stage 5: Read replicas and sharding (thousands of tenants). At this scale, you may need database read replicas for read-heavy tenant workloads. This is beyond Deploynix's built-in management and requires custom database architecture.

The beauty of this progression is that each stage is incremental. You do not need to re-architect your application — you add infrastructure components as your tenant count and traffic demand them.

Step 9: Tenant Onboarding Flow

When a new tenant signs up, Stancl/Tenancy creates a new database, runs tenant migrations, and seeds initial data. This process must work reliably in production.

Ensure the tenant creation process is queued for resilience:

// Creating a tenant
$tenant = Tenant::create(['id' => 'acme']);
$tenant->domains()->create(['domain' => 'acme.yourapp.com']);
Enter fullscreen mode Exit fullscreen mode

Stancl/Tenancy triggers database creation and migration automatically. On Deploynix, the database user has the necessary permissions (configured in Step 1) to create new databases.

Test the onboarding flow after deployment:

  1. Create a test tenant through your application's signup flow.
  2. Verify the tenant database is created.
  3. Verify tenant migrations have run.
  4. Verify the tenant subdomain resolves correctly.
  5. Log in as a tenant user and verify Livewire components render correctly.
  6. Clean up the test tenant.

Go-Live Checklist

Before launching your multi-tenant SaaS:

  • Central database migrations are current.
  • Tenant migrations are current for all tenants.
  • Wildcard SSL certificate is active.
  • Queue workers are running and tenant-aware.
  • Scheduled tasks are registered and working.
  • Database backups are configured for central and tenant databases.
  • Server monitoring and health alerts are active.
  • Error tracking is configured.
  • Tenant onboarding flow works end-to-end.
  • Livewire assets are published and functioning.
  • APP_DEBUG=false and APP_ENV=production.

Multi-tenant SaaS deployment is complex, but it is not complicated when you have the right infrastructure. Deploynix handles server provisioning, deployment, SSL, monitoring, and backups. Stancl/Tenancy handles tenant isolation, database management, and context switching. Your job is to build the product.

Top comments (0)