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 Preflight Checks Laravel Package

kirschbaum-development/laravel-preflight-checks

Run preflight checks in Laravel before deploys or critical operations. Define custom checks to validate config, environment, and dependencies, then get clear pass/fail results so problems surface early instead of in production.

View on GitHub
Deep Wiki
Context7

Getting Started

Install pinned, not ranged. This is 0.x with 3 stars and 0 dependents — a caret constraint is a trap.

composer require kirschbaum-development/laravel-preflight-checks:0.6.0

Before committing, open the resolved composer.json constraint and confirm the Laravel/PHP ranges actually include your stack. 0.6.0 advertises Laravel 13 / PHP 8.5 support, but a widened constraint is not proof of a green CI matrix — check the workflow files on the tag, not the readme.

Find the entrypoint before reading the source. The package is small enough that the source is the documentation, but start by asking Artisan:

php artisan list | grep -i preflight
php artisan vendor:publish --provider="Kirschbaum\PreflightChecks\PreflightChecksServiceProvider"

Publish tags and config are worth checking (list providers if the publish command is a no-op):

php artisan vendor:publish --list-tags

Read these in this order: the service provider (tells you what gets registered and how checks are discovered), the config file (registration mechanism and defaults), then one or two bundled check classes — those are your template for authoring your own.

First use case: a read-only audit of staging. Not a gate. Run the default suite against a known-good staging environment and read the output. You are answering two questions: what does a green run look like, and does the command exit non-zero on failure? Then deliberately break one thing (rename a .env key, revoke storage permissions) and confirm it goes red. A preflight suite that passes on a broken environment is worse than no suite — it manufactures confidence. Do this before it ever touches a pipeline.

Add a composer script so it's one command for everyone:

"scripts": {
    "preflight": "@php artisan preflight:check"
}

Implementation Patterns

Never author checks in vendor/. Create a project-owned namespace — app/Support/Preflight/, or better, a small internal package if you have several apps. Everything in that directory is yours; everything in vendor is replaceable. This is the single decision that keeps your exit cost at "a day of work" rather than "a project."

namespace App\Support\Preflight;

use Kirschbaum\PreflightChecks\...; // whatever the base class turns out to be
use Illuminate\Support\Facades\DB;

final class DatabaseHasMigrations extends Check
{
    public function name(): string { return 'database-migrations-applied'; }

    public function check(): mixed
    {
        $pending = DB::select('select * from migrations limit 0');
        // return based on your own predicate
    }
}

Write checks from incident history, not imagination. The framework is commodity; your checks are the differentiator. Every production incident that could have been caught by inspecting configuration gets a check. Things that earn their keep on a typical Laravel app:

  • Required config() values are non-null and non-empty after config:cache (the classic drift failure)
  • Storage and bootstrap/cache directories are writable by the runtime user
  • Queue connection is reachable and the expected worker/monitor is alive
  • Redis/cache reachable, with the expected prefix so staging doesn't clobber prod keys
  • APP_KEY present and correctly base64-decoded
  • APP_DEBUG is false in production — cheap, catches a genuinely expensive mistake
  • Scheduled-task heartbeat file is fresh (catches a dead cron, which nothing else will)

Wire into CI as advisory first, blocking later. For one to two weeks, let it warn:

- name: Preflight (advisory)
  run: php artisan preflight:check || true

Promote to blocking only after it has demonstrated a true positive — i.e. it caught something real that a human would otherwise have shipped. Always keep a documented bypass for 2 a.m. hotfixes (--skip-preflight flag or an env guard), because a gate with no escape hatch gets ripped out wholesale the first time it blocks an emergency.

Distinguish contexts, don't fight them. The same check suite cannot be equally valid in local dev, CI, a build container, and a production boot. Most packages of this shape support named suites or per-check enablement — use it:

Context What belongs
Local dev / pre-commit PHP version, extensions, .env completeness. Fast, no network.
CI Everything non-network. Mock or skip DB/Redis unless CI provisions them.
Post-deploy smoke Real connectivity, real writability, real migrations.
Container entrypoint Only cheap, non-blocking checks — never let a network probe gate a pod start.

Use it as executable onboarding documentation. A committed preflight suite tells a new engineer, in code, what "this app is ready" means. Point at it in the README's setup section. It pays for itself the first time a rebuilt staging box comes up wrong and someone gets a list instead of a mystery.

Post-incident ritual. Add a line to your retro template: "What check would have caught this?" If the answer is achievable by inspecting config or connectivity, write it that week. That practice, not the dependency, is the deliverable.

Gotchas and Tips

env() lies once config is cached. If any check reads env('SOMETHING'), it will return null in a cached deploy — and so will a check that "verifies the env var is set." Verify config() keys resolved to real values instead. This is the most common way preflight checks silently pass on broken environments.

Beware checks that only validate presence, not effect. APP_URL being non-empty is a weak check; APP_URL matching the known hostname for that environment is a strong one. Same for queue names, bucket names, and mailers — staging and prod drift by value, not by existence.

Never echo secret values in failure output. Check for presence, length, and format only. A preflight failure that dumps a token into CI logs is an incident, not a diagnostic. If the package's built-in checks print values, grep the source before enabling them on a repo whose logs are widely readable.

Boot-time checks are dangerous. If the package supports running checks during application boot, keep to microsecond-cost checks there. A network probe or a DNS lookup in a service provider turns a slow dependency into a hung request. Reserve connectivity checks for the CLI invocation.

Verify exit codes and non-interactivity explicitly. Before trusting it in a pipeline, run it unattended with stdin closed and assert $?. A command that prompts, or that returns 0 while printing failures, is a gate that never fires. Test the failure path, not just the success path:

php artisan preflight:check; echo "exit=$?"

Don't let CI environment gaps become false reds. A DB-connectivity check in a CI job with no database service will fail every build, and a suite that always fails gets ignored within a week — which is how gates die. Scope checks per context or gate them on the presence of the required service.

Pin exactly and read every changelog. 0.6.0 is a compatibility release from 0.5.1 — single PR, no feature or deprecation entries, the cheapest upgrade class. Expect roughly one genuinely breaking minor per year while pre-1.0 (class renames, config key moves). Treat the upgrade as a scheduled task with a test pass, not a composer update.

Confirm what 0.6.0 still supports before assuming a drop-in. A compatibility release that adds Laravel 13 may or may not retain older majors. If the app isn't on a recent Laravel/PHP, this may be a post-upgrade addition rather than a pre-upgrade one.

This is a point-in-time check, not monitoring. It tells you the environment was correct at deploy time; it does not tell you a worker died at 3 a.m. Do not let it displace uptime probes or heartbeat alerting — complementary, not a substitute.

Keep a fallback in your head. Single maintainer, agency-backed, no SLA. The framework is thin enough that an internal Artisan command replicating it is a day's work provided your checks live in your own namespace and the package's base class is the only thing you subclass. Every time you're tempted to extend a vendor class rather than your own, ask what that costs you at the next major.

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.
mehedimi/laravel-amp-mail
happones/laravel-vue-i18n-generator
jwerd/inertia-table
siberfx/flysystem-wasabi
hollyit/token-replace
ippanelcom/laravel-sdk
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel