larassn/laravel-pulse-graphql
Laravel Pulse GraphQL adds GraphQL monitoring cards to Laravel Pulse, letting you track query counts, execution times, slow requests, and errors so you can quickly diagnose performance bottlenecks and regressions in your GraphQL API directly from the Pulse dashboard.
Install via Composer and register the recorder in your Pulse configuration:
composer require larassn/laravel-pulse-graphql
Publish the package config if you need to tune sampling or naming:
php artisan vendor:publish --tag="pulse-graphql-config"
Then add the recorder to config/pulse.php under recorders:
'recorders' => [
// ...
\Larassn\PulseGraphQL\Recorders\GraphQLRecorder::class => [
'enabled' => true,
'sample_rate' => 1,
],
],
Clear config cache (php artisan config:clear) and open /pulse — you should see GraphQL-specific cards alongside the standard slow-queries and requests panels.
Where to look first: open the package's own config file (config/pulse-graphql.php) right after publishing. It typically controls the recorder key, sample rate, and which GraphQL operations to include. The src/Recorders/ directory in vendor/larassn/laravel-pulse-graphql is the fastest way to confirm exactly which resolver hooks the package listens to.
First use case: point the recorder at your existing GraphQL endpoint (Lighthouse, Rebing, or a hand-rolled controller), execute a handful of queries through your app, and confirm the Pulse card populates before wiring anything else. Sampling at 1 locally makes this deterministic.
v2.1.0 only adds Laravel 13 support — no new APIs, no breaking changes. If you are on Laravel 12 or below, there is no functional reason to upgrade from v2.0.0; if you are preparing a Laravel 13 upgrade, this is the version to pin.
Scope the recorder to one endpoint. Register it only on your /graphql route group (or guard it behind a config flag) so it does not instrument unrelated resolvers. This keeps Pulse's graphql_* tables clean and avoids sampling noise from every request.
Tune the sample rate per environment. Use 1 in local and staging, and something in the 0.05–0.25 range in production. Over-sampling inflates the Pulse entries table and makes the card's averages jumpy rather than more accurate.
Pair with the built-in SlowRequests recorder. The GraphQL card tells you which operation is slow; SlowRequests tells you which HTTP route delivered it. Together they distinguish "the resolver is slow" from "the surrounding middleware/controller is slow."
Correlate with slow queries. If your GraphQL card shows a p95 spike on a specific mutation, cross-check the SlowQueries card at the same timestamp. Most GraphQL latency in Laravel apps is N+1 Eloquent calls inside a resolver, not the GraphQL layer itself.
Tag operations by name. Give your client-side operations stable names (query GetUserProfile, not anonymous). The recorder groups by operation name, so anonymous or dynamically-composed queries collapse into an unhelpful bucket and the card loses its diagnostic value.
Use it during load tests, not just in prod firefighting. Run a k6 or Artillery scenario against staging with sampling at 1, and the Pulse card becomes a cheap per-operation latency profile — useful when deciding whether to batch, cache, or add a DataLoader.
Laravel 13 is the only behavioural change in v2.1.0. Treat the upgrade from v2.0.0 as a compatibility bump: re-run composer update larassn/laravel-pulse-graphql and verify your composer.json constraint allows it (^2.1). If your app is pinned to Laravel 12, v2.1.0 still installs, but the Laravel 13 support it advertises does nothing for you.
Recorder changes need config:clear. Pulse resolves recorders from cached config in deployed environments. A newly-added recorder that shows up locally but not in production is almost always a stale config cache, not a broken package.
Pulse itself must be installed, migrated, and non-local-only. The pulse_values and pulse_entries tables need to exist, and Pulse::check gates non-local access. If the GraphQL card is blank while other cards work, check the dashboard's authorisation gate before debugging the package.
Card thresholds are presentation-layer. If the GraphQL card reads "healthy" while your APM shows pain, the package is likely using a configurable threshold rather than your target SLA. Adjust it in the config file, or read the underlying entries directly with php artisan tinker against the pulse_entries table for ground truth.
The recorder observes, it does not wrap your server. It hooks the GraphQL execution path; it will not capture queries that fail during schema validation or that never reach a resolver. Error rates on the card reflect execution errors, not bad client requests — don't use it as your only error-rate signal.
No extension points added in v2.1.0. If you need custom grouping (e.g. by persisted query hash or by tenant), you will be extending the recorder class rather than configuring it. Fork-adjacent: subclass the recorder, register the subclass in config/pulse.php, and re-check on the next minor release in case upstream adds the hook you need.
Upgrade hygiene. Pin ^2.1 rather than ^2.0 if you are moving to Laravel 13, then run the full test suite and open /pulse once locally. The release is a single-commit dependency bump, so the realistic failure mode is a transitive version conflict in composer.lock, not a runtime regression.
How can I help you explore Laravel packages today?