Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Xhprof Laravel Package

bavix/laravel-xhprof

Integrates XHProf profiling into Laravel so you can capture and inspect performance data for requests and identify slow endpoints. Provides simple configuration and middleware for lightweight, request-level profiling.

View on GitHub
Deep Wiki
Context7

Getting Started

bavix/laravel-xhprof wraps the XHProf (or tideways_xhprof) PHP profiler so a Laravel app can be profiled per-request and the resulting callgraphs browsed from a built-in UI. Release 2.1.0 is a compatibility release — it adds Laravel 13 support alongside the existing 10/11/12 range, plus dependabot workflow bumps. There are no breaking changes, so upgrading from 2.0.x is a routine composer update.

  1. Confirm the runtime prerequisite first. The package is useless without the underlying extension. Check php -m | grep -i xhprof (or tideways_xhprof) before installing anything, and check the extension builds against your PHP version — that is the step teams most often get stuck on.
  2. composer require bavix/laravel-xhprof
  3. Publish the config: php artisan vendor:publish --tag=xhprof (confirm the tag with php artisan vendor:publish if it differs). The config lands at config/xhprof.php.
  4. Start with profiling off globally and enable it only for a local/staging environment, e.g. XHPROF_ENABLED=true in .env.
  5. First use case: enable profiling, hit a single slow route, then open the profiling UI route the package registers (typically under /xhprof) and read the wall-time and inclusive/exclusive time columns for the slowest frames. That single loop — enable, hit, inspect — is 90% of day-to-day use.

Look first at: config/xhprof.php (what gets profiled and where profiles are stored), then the middleware the package auto-registers — that is the thing that decides whether your request is captured at all.

Implementation Patterns

Targeted profiling via middleware. Rather than profiling everything, keep global capture off and apply the package middleware to the specific route groups you care about (a slow checkout endpoint, an API group under load). This keeps profile storage small and keeps overhead away from high-traffic paths.

Global sampling mode. For "what's slow in production-like traffic" work, enable the global capture option together with a sampling rate below 1 so only a fraction of requests are profiled. Pair this with a short retention window so profile files don't accumulate.

Environment-gated config. Drive the config from env rather than editing config/xhprof.php directly, so local, CI, and staging can differ without merge conflicts. Guard the enable flag with something that can never be true in production unless deliberately set.

Before/after optimisation loop. Snapshot a profile on the current code, apply the optimisation, snapshot again, and compare the same route with comparable input. XHProf callgraphs are only meaningful as a comparison — absolute wall times drift with machine state.

Pair with query logging. XHProf shows PHP call frames; it does not show SQL. For anything database-shaped, read the profile for the PHP frame that's hot, then reproduce with DB::listen or Telescope to see the query. The two together are what actually find the problem.

Storage lifecycle in CI and local dev. Add the profile storage directory to .gitignore, and schedule the package's clear/prune command (check php artisan list xhprof) so a long-lived dev box doesn't fill its disk. In CI, leave profiling disabled entirely.

Upgrade path for 2.1.0. If you're on Laravel 13 you were previously blocked; 2.1.0 unblocks you. Update the constraint, run the suite, and smoke-test one profiled request — the release is dependency/CI churn plus framework support, so the risk surface is the framework matrix, not the package internals.

Gotchas and Tips

  • The extension, not the package, is the failure point. A missing or unloadable xhprof/tideways_xhprof extension usually manifests as silent non-profiling or a fatal on the first profiled request rather than a clean install-time error. Verify the extension independently with a one-line xhprof_enable() script before blaming the package.
  • Silent no-ops. If profiling is enabled but no profiles appear, check in this order: global enable flag, sampling rate, whether the middleware is actually attached to that route (route caching can stale it), and whether the storage directory is writable by the PHP-FPM user. php artisan route:clear/config:clear after config edits resolves a surprising number of "it's not working" reports.
  • Overhead is real. Full capture on a busy endpoint can multiply response time and memory. Never leave global capture at sampling 1 in production; use the middleware on selected routes or a low sample rate.
  • Profile files are large and numerous. A directory of raw callgraphs grows fast. Set retention deliberately and exclude the storage path from deploys and backups.
  • UI exposure. The bundled viewer route is a debugging tool — restrict it to non-production environments and behind auth. It exposes internal call structure and file paths.
  • Long-running processes. Under Octane or queue workers, profiler state can leak across requests if enabled globally; prefer per-request middleware capture, and disable profiling in workers unless you're specifically profiling a job.
  • Config cache. config/xhprof.php read through env vars requires php artisan config:cache to be re-run on deploy; a stale cache is the classic reason an env toggle "does nothing".
  • Version constraints. Confirm the illuminate/* and PHP constraints in composer.json before bumping — 2.1.0 widens framework support but does not change your PHP floor.
  • Extension points. The config's storage driver and the middleware binding are the two places to customise; extending the package usually means writing your own middleware wrapper or swapping the storage path rather than forking.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle