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 Self Diagnosis Laravel Package

beyondcode/laravel-self-diagnosis

Run a series of checks to verify your server meets Laravel's requirements. This package provides an artisan command and web interface to diagnose PHP version, extensions, folder permissions, and other environment issues before deployment. Catch problems early and ship with confidence.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and first run.

composer require beyondcode/laravel-self-diagnosis --dev
php artisan diagnose

Auto-discovery registers the service provider. There is nothing to migrate, no assets to publish, and no schema. The command works immediately with the built-in checks: PHP version, required extensions, writable storage/ and bootstrap/cache/, .env presence, APP_KEY, storage symlink, and database connectivity.

Note the --dev above. Whether you put this in require or require-dev is the first real decision: if you want the diagnostics page available to operators in a self-hosted production install, it belongs in require; if it is a developer and pipeline tool only, require-dev keeps it out of production vendor trees entirely.

Publish the config when you need to change anything.

php artisan vendor:publish --tag=config

That gives you config/self-diagnosis.php with the check list and route settings. Read it before you touch it — the defaults define a route, its middleware, and which checks run.

First use case worth wiring. Run php artisan diagnose on a machine where the app is broken but nobody knows why, before you start reading logs. A stale APP_KEY, a non-writable storage/, or a missing symlink produces a confusing error in the application and an unambiguous line here. This is the highest-value, lowest-effort adoption step and it costs you nothing but the Composer install.

Where to look first in the codebase. The published config file, then the package's src/Checks/ directory to see what a built-in check looks like before you write your own, then the service provider to understand what gets registered and under what conditions.

Implementation Patterns

CLI in the deploy pipeline (the pattern that actually earns its keep). The command is the durable integration; the web page is the convenience. Add a post-deploy smoke step:

php artisan diagnose || echo "diagnostics failed — investigate before promoting"

Be deliberate about whether a failure blocks the deploy. A hard set -e on diagnostics means a transient database blip fails a release that would otherwise be fine. Most teams want the output logged and surfaced, with blocking reserved for specific checks. If you need blocking, run targeted checks rather than the whole list.

Gate the route before it ever reaches a shared environment. The page renders PHP version, extension inventory, and filesystem layout to anyone who loads it. Decide the access policy as a task with an owner — auth middleware, IP allowlist, or environment-gated off — and verify the "off" path actually works rather than assuming it. Configuring middleware through the published config is the normal mechanism; do this in the same commit that adds the dependency, not in a follow-up ticket.

Custom checks for domain preconditions. Built-ins cover Laravel-generic requirements; your application has its own. Anything that must be true for the app to function — a required queue connection, a third-party credential present, a writable upload volume outside storage/, an expected cache driver — belongs in a check. Custom checks are plain classes or closures, which means they are ordinary code you can unit test:

// A check that asserts a required external credential is configured
// rather than discovering its absence at the first API call.

Keep each check narrow and name it after the failure it detects. A check called StorageWritable that also verifies symlinks is a check nobody can act on when it goes red.

Onboarding as a documented first step. Put php artisan diagnose in the README's setup instructions for new engineers and in the runbook for support agents. The support-agent case is the underrated one: a non-engineer who can run one command and read a red/green list deflects a whole class of "the app is broken" tickets before they reach an engineer. If you adopt this for triage, instrument it — tickets deflected and time-to-triage — so the value is measurable rather than asserted.

Pair it with, don't confuse it for, runtime health. This answers "is this environment correctly configured right now." It knows nothing about queue depth, worker liveness, scheduler heartbeats, or third-party latency. If you need those, that is a separate framework (Spatie's Laravel Health is the usual comparison) and a separate decision. Running both is reasonable; expecting one to cover the other is not.

Gotchas and Tips

CLI and FPM disagree, and the CLI result is the one you'll mistakenly trust. Extension and ini state commonly differ between SAPIs. A green php artisan diagnose from a shell does not guarantee a green web request — the deploy user's php -m is not necessarily the FPM pool's extension set, and open_basedir or ini overrides may differ. After any environment change, run the diagnostics through the surface that matters. If the web page is your operator interface, load the page; don't infer its result from the command.

The silent downgrade during composer update. Verify your PHP and Laravel versions against the package's actual composer.json constraints, not the changelog and not the CI matrix. Compatibility is sometimes asserted by testing rather than by widening the runtime constraint, and when constraints don't admit your framework version Composer quietly resolves an older tag instead of failing loudly. Pin to the tag you validated. The 3.1.0 release notes in particular carry a second entry labeled only "Dev," which is opaque enough that reading the diff on minor bumps is warranted here rather than trusting the summary — confirm whether it touched checks, route middleware, or config defaults.

Published config silently drifts from vendor defaults. Laravel's merged config means new keys added by the package apply silently even if your published copy predates them — convenient, but it also means a changed default can reach production without appearing in your diff. After each update where you have a published config, diff it against the vendor copy. Treat a changed default in the diagnostics config as something to review, not something to absorb.

Consider what happens when a check throws. A check that raises an exception instead of returning a failure should not take down the request or the command. Confirm this behavior in your version before you rely on the page in a customer-facing context — and write custom checks that return failures rather than throwing, since that discipline is entirely within your control.

Access control is your bug, not the package's. The package gives you a route; it does not decide who may load it. An unauthenticated diagnostics page in production is a disclosure finding with your name on it. The safest posture if your security model can't tolerate the endpoint existing at all is to use the command only and leave the route disabled.

Plan the exit as part of the adoption. This is a small dependency with single-maintainer lineage in a non-critical path. The correct mental model is that it can be removed in an afternoon: one service provider, one config file, no migrations, no background jobs, no persistence. Keep it that way — resist the temptation to build application logic on top of it or to treat its output as an audit trail. It is operator-facing, not compliance-grade evidence.

Installed but never executed is the standard failure mode. A diagnostics package that nobody runs has a value of zero. Wire the command into a post-deploy step or the onboarding runbook in the same change that adds the dependency; a README mention alone will be forgotten within two sprints.

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.
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route