Skip to content

Senior Laravel Developer: production APIs, multi-tenancy and realtime

How I build Laravel backends that run a business: a service layer behind thin controllers, tenant isolation enforced by the database query rather than by discipline, queued work, and websockets that push a signal instead of data.

A production Laravel application is one where the framework has stopped being the interesting part. The decisions that matter are where business logic lives, how a tenant is isolated, what happens off the request, and how the client learns something changed — and Laravel gives you a first-class answer to each.

Thin controllers, a real service layer

Controllers parse, validate and return status codes. Services hold the business rules and own the transaction boundary. Models and scopes talk to the database. The payoff is that a rule can be tested without booting HTTP, and a change to the API shape never reaches the schema.

Authentication through Laravel Sanctum, with authorization expressed as policies rather than conditionals scattered through controllers.

Multi-tenancy that fails loudly

Tenant identity comes from the authenticated token, never from a parameter a client could change. A global scope applies it to every query, so a forgotten filter returns nothing rather than another customer’s rows.

This is the difference between a system that is multi-tenant and one that merely has a tenant_id column: the isolation is a property of the query layer, not of whoever wrote the last endpoint.

Queues, schedulers and Reverb

Notifications, reminders and review requests run on a queue worker and a scheduler, so nothing slow happens inside a request a person is waiting on.

For live screens, Laravel Reverb broadcasts a small “this changed” signal on a private per-tenant channel and the client refetches. Pushing the signal rather than the payload keeps authorization in one place and the socket cheap.

What keeps it honest

PHPUnit for behaviour, Larastan for the types PHP will not check on its own, and Laravel Pint so formatting is never a review comment.

See the SalonSync case study for all of this running in production: a multi-tenant SaaS for barbershops and salons.

Common questions about building with Laravel

Is Laravel suitable for a production SaaS, or just prototypes?

It runs production SaaS. The parts a SaaS actually needs — authentication, authorization policies, queues, a scheduler, database migrations, websockets, a testing story — are first-party rather than assembled from packages. SalonSync is a live multi-tenant platform built this way.

How do you isolate tenants in a Laravel application?

A global scope on every tenant-owned model, fed by the identity in the authenticated token. Because the scope is applied at the query layer, an endpoint that forgets to filter returns an empty set instead of another customer’s data. Tenant identity never comes from the request body.

When should work move to a Laravel queue?

Whenever the person who triggered it does not need the result to continue — sending a notification, requesting a review, calling a third-party API. The test is whether a failure should block the response. If it should not, it belongs on a queue with retries and a failed-jobs table.

Why broadcast a signal over websockets instead of the data?

Because the payload would need its own authorization. Sending “something on this channel changed” and letting the client refetch through the normal API means permissions are enforced once, in the endpoint that already does it, and the socket never carries anything a listener should not see.