
Table of Contents
By Khimananda Oli | Last reviewed: August 2026
Implementing GraphQL Subscriptions with Laravel Lighthouse transforms a standard request-response API into a reactive system capable of pushing data instantly to connected clients. While Lighthouse abstracts much of the protocol complexity, production deployments require careful configuration of broadcasting drivers, Redis infrastructure, and authorization guards to prevent performance degradation or security leaks. This guide covers the exact architecture and configuration needed to run reliable subscriptions in 2026, moving beyond basic tutorials to address scaling and observability.
How does the architecture for GraphQL Subscriptions with Laravel Lighthouse work?
Understanding the data flow is critical before writing code. Unlike REST or standard GraphQL queries, subscriptions maintain a persistent connection. In the Lighthouse ecosystem, this involves three distinct layers: the WebSocket server (Reverb/Pusher), the Pub/Sub backend (Redis), and the application logic (Laravel). When a client subscribes, Lighthouse registers interest via the broadcast driver. When an event occurs, Laravel publishes to Redis, which fan-outs the message to all connected WebSocket servers, finally delivering the payload to authorized clients.
This decoupled architecture is non-negotiable for production. If you skip Redis and use the default array driver, subscriptions will only work on the specific server instance that handled the initial handshake. For teams managing infrastructure similar to real-time Laravel with Reverb, ensuring this pub/sub backbone is correctly provisioned prevents silent failures where users simply stop receiving updates during horizontal scaling events.
How do you configure Redis and broadcasting for Lighthouse subscriptions?
Lighthouse relies entirely on Laravel's native broadcasting system. The most common failure point in 2026 is misconfiguring the underlying transport. While Pusher remains a valid managed option, self-hosted teams now standardize on Laravel Reverb paired with Redis. This combination provides enterprise-grade reliability without third-party vendor lock-in or per-message fees that destroy unit economics at scale.
Configuring Redis for Horizontal Scaling
Your config/database.php must explicitly define a Redis cluster or replica set if running multiple nodes. For subscriptions, latency matters more than persistence. Ensure your Redis configuration uses TCP keepalive and appropriate timeout settings to prevent zombie connections from exhausting file descriptors.
<?php
// config/database.php
'redis' => [
'client' => env('REDIS_CLIENT', 'phpredis'),
'options' => [
'cluster' => env('REDIS_CLUSTER', 'redis'),
'prefix' => env('REDIS_PREFIX', 'lighthouse_'),
'persistent' => true, // Critical for subscription performance
],
'default' => [
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_DB', '0'),
'read_write_timeout' => 60,
],
], Broadcasting Driver Configuration
In .env, set BROADCAST_CONNECTION=reverb. Verify your config/broadcasting.php includes the Reverb configuration block. A frequent mistake is leaving the old Pusher config active while switching drivers; Lighthouse reads the active connection strictly. If you are deploying to Kubernetes or Docker Swarm, ensure the Reverb server runs as a separate long-lived process, not embedded within your PHP-FPM workers. For deeper infrastructure context, review Laravel performance optimization techniques to ensure your broadcast layer doesn't contend with HTTP request processing.
How do you define and authorize GraphQL Subscriptions with Laravel Lighthouse?
Defining the schema is straightforward; securing it is where engineering discipline separates prototypes from production systems. Every subscription field in your schema maps to a dedicated PHP class. Never expose a subscription without an explicit authorization check. In multi-tenant environments common in Nepal's growing fintech sector, leaking subscription data across tenant boundaries is a critical compliance violation.
Schema Definition
Use the @subscription directive to bind a schema field to a resolver class. Keep subscription payloads minimal; fetch heavy relational data via nested queries only when necessary to reduce bandwidth.
type Subscription {
orderStatusChanged(order_id: ID!): Order
@subscription(class: "App\\GraphQL\\Subscriptions\\OrderStatusChanged")
teamNotification(team_id: ID!): Notification
@subscription(class: "App\\GraphQL\\Subscriptions\\TeamNotification")
} Implementing Authorization Logic
The authorize() method runs on every subscription attempt. Return false to reject the connection immediately. This is distinct from query authorization; it protects the persistent socket itself.
<?php
namespace App\GraphQL\Subscriptions;
use Nuwave\Lighthouse\Subscriptions\Subscription;
use Illuminate\Http\Request;
class OrderStatusChanged extends Subscription
{
public function authorize(Request $request): bool
{
$user = $request->user();
$orderId = $this->args['order_id'];
// Strict ownership or role check
return $user && (
$user->orders()->where('id', $orderId)->exists() ||
$user->hasRole('admin')
);
}
public function resolve($root): ?array
{
return $root;
}
} Always validate arguments against the authenticated user's scope. Relying solely on frontend filtering is a security anti-pattern. For teams handling sensitive data, integrating these checks with OWASP Top 10 security practices ensures your real-time layer meets audit requirements.
How do you trigger subscription events efficiently in production?
Triggering subscriptions synchronously inside HTTP requests creates backpressure. If your WebSocket server experiences latency, your entire API response slows down. Always dispatch subscription broadcasts via Laravel Queues. This decouples the user-facing transaction from the real-time notification delivery, maintaining sub-100ms API response times even during broadcast spikes.
Using Model Observers for Clean Triggers
Avoid scattering broadcast() calls throughout service classes. Use Eloquent Model Observers to centralize subscription triggers. This ensures consistency regardless of whether the update came from an API call, a CLI command, or a scheduled job.
<?php
namespace App\Observers;
use App\Models\Order;
use Nuwave\Lighthouse\Subscriptions\SubscriptionBroadcaster;
class OrderObserver
{
public function updated(Order $order): void
{
if ($order->wasChanged('status')) {
// Dispatches asynchronously if configured in lighthouse.php
SubscriptionBroadcaster::broadcast(
'orderStatusChanged',
$order,
['order_id' => $order->id]
);
}
}
} Configure 'broadcast_mode' => 'async' in config/lighthouse.php to enforce queue-based broadcasting globally. This single setting prevents more production incidents than almost any other configuration in the Lighthouse stack.
How do you debug and monitor GraphQL Subscriptions with Laravel Lighthouse?
Subscriptions are notoriously difficult to debug because failures are silent. Unlike HTTP 500 errors, a broken subscription simply stops delivering data. Implement structured logging specifically for broadcast events. Track subscription counts per channel, authorization rejection rates, and queue lag. These metrics form the foundation of your observability strategy.
| Metric | Healthy Range | Warning Sign | Action |
|---|---|---|---|
| Active Connections | Stable / Growing | Sudden Drop | Check Reverb/Proxy logs |
| Broadcast Queue Lag | < 5 seconds | > 30 seconds | Scale queue workers |
| Auth Rejection Rate | < 1% | > 5% | Review client token refresh |
| Redis Memory Usage | < 70% capacity | > 85% capacity | Evict stale subscription keys |
For local development, use Laravel Telescope to inspect broadcast events. In production, integrate with Prometheus and Grafana. Expose Reverb metrics via its built-in health endpoint. If you are building comprehensive monitoring, reference Prometheus and Grafana full monitoring stack to visualize subscription health alongside traditional application metrics. Without this visibility, you are operating blind.
What are the best practices for scaling GraphQL Subscriptions with Laravel Lighthouse?
Scaling subscriptions requires addressing both connection limits and message throughput. Each Reverb worker can handle approximately 10,000 concurrent connections depending on payload size and hardware. Beyond this threshold, deploy additional Reverb instances behind a load balancer. Redis handles the coordination automatically, provided you have configured it correctly as described earlier.
- Filter Aggressively: Never broadcast global channels. Always scope subscriptions to specific entities or tenants to reduce fan-out overhead.
- Payload Minimization: Send only IDs and changed fields. Let clients refetch full details if needed. This reduces Redis memory pressure and network bandwidth.
- Connection Limits: Implement rate limiting on the WebSocket endpoint itself. Malicious or buggy clients can exhaust server resources by opening thousands of sockets.
- Graceful Degradation: Design clients to fall back to polling if the WebSocket connection fails. Subscriptions are an enhancement, not a hard dependency for core functionality.
- Testing Infrastructure: Write integration tests that verify subscription delivery end-to-end. Unit testing resolvers is insufficient; you must validate the broadcast pipeline.
For teams serving Nepali markets with variable network conditions, prioritize payload efficiency above all else. High-latency connections drop frequently; smaller payloads reconnect faster and consume less mobile data. This practical consideration often matters more than theoretical maximum throughput benchmarks.
Next Steps for Production GraphQL Subscriptions
GraphQL Subscriptions with Laravel Lighthouse provide powerful real-time capabilities when implemented with architectural discipline. Start with Redis-backed Reverb, enforce async broadcasting, and instrument observability before shipping to production. The difference between a demo and a resilient system lies entirely in these operational details. If your team needs assistance architecting scalable real-time infrastructure or auditing existing subscription implementations, reach out to discuss your specific requirements.