Laravel Packages

Laravel Doctor: Diagnose Your App With One Artisan Command

Published
Laravel Doctor: Diagnose Your App With One Artisan Command image

Laravel Doctor was announced at Laracon US 2026 in Boston, adding an artisan doctor command that runs health checks against your application. From the announcement:

Artisan doctor runs a set of health checks against your Laravel application: is your APP_KEY set, does your PHP version match what Composer expects, are your required extensions installed, and is your environment configuration complete? Where it can fix an issue automatically, it does. Where it can't, it tells you exactly what's wrong.

Diagnosing a broken Laravel install has usually meant checking a mental list: is .env there, is the key generated, is storage/ writable, is the queue connection not sync in production. Doctor turns that list into code, and gives packages a place to add their own entries to it.

How It Works

Each diagnostic is a single class that inspects one thing and returns one of six statuses: pass, notice, warn, fail, skip, or error. Out of the box, the command exits with a non-zero status if anything fails or errors occur. If you want warnings to fail a build too, pass --fail-on=warn. If you only want the report and never a failed exit code, use --fail-on=never.

The shipped suite covers:

  • Environment: .env presence, APP_KEY, PHP version against the composer.json constraint, required and recommended extensions, and timezone.
  • Composer: dependencies installed, optimized autoload files can be dumped, and repairable composer.lock problems.
  • Configuration: config files load and cache, values required by the active drivers are set, and bootstrap cache state.
  • Database: the default connection is reachable, the SQLite file exists when needed, and pending migrations.
  • Cache, queue, scheduler, and session: configured drivers are reachable, Redis connections are checked, and scheduled tasks are surfaced as a notice.
  • Storage: the default disk is reachable, required directories are writable, and the storage:link symlink exists.
  • Security: debug mode matches the environment, .env is git ignored, and dependencies are audited.

Some of these can't be judged in isolation, so Doctor resolves your app into one of two modes, local or production, and the mode decides whether something counts as a problem at all. A sync queue connection passes locally and warns you in production. Missing bootstrap caches warn in production but pass locally, while caches that are present pass in production and produce a notice locally, since a stale cache is a common reason recent changes do not show up while you're working. Laravel Doctor knows local, production, and staging out of the box, and anything it does not recognise is held to production expectations.

Getting Started

Install it as a dev dependency:

composer require laravel/doctor --dev

Then run it:

php artisan doctor

When a failing diagnostic can be repaired, Doctor reports the problem and prompts you before doing anything:

Storage is writable: The application cannot write to every required storage directory.
 
Make the storage directories writable? (yes/no) [yes]

php artisan doctor --fix skips the prompting. It can create a missing .env, generate APP_KEY, turn off debug mode in production, add .env to .gitignore, create the public storage link, and repair storage directory permissions. Other repairs require a human to choose among options, such as which cache store to switch to when the default one is unreachable. Those show up as a select list when you run the command interactively, and fall back to ordinary failures under --fix.

Diagnostics can be filtered by class name, group, package, or package wildcard:

php artisan doctor --only=security
 
php artisan doctor --except=laravel/*

If you always want the same selectors applied, publish the config file with php artisan vendor:publish --tag=doctor-config and set them there.

Custom Diagnostics

Packages can register diagnostics from their service provider through the Doctor facade, the same way an application would:

use Laravel\Doctor\Facades\Doctor;
use Vendor\Package\Diagnostics\HorizonIsRunning;
 
public function boot(): void
{
Doctor::diagnostic(HorizonIsRunning::class);
}

Reports show which Composer package each diagnostic came from:

[fail] Storage is writable (laravel/doctor): The application cannot write to every required storage directory.
[pass] SQLite database exists (acme/application): The SQLite database file exists.
[warn] Horizon is running (laravel/horizon): Horizon is not currently running.

Running php artisan make:diagnostic HorizonIsRunning scaffolds one into app/Doctor/Diagnostics. It extends Laravel\Doctor\Diagnostic and implements a check() method that returns a DiagnosticResult. The wording lives separately in a messages() method, where each Message::make() holds a summary, remediation text, documentation links, and the confirmation prompt shown before a fix runs.

If your check can repair what it finds, implement Laravel\Doctor\Contracts\Fixable and tag the specific failures with ->fixable(). That method also accepts an EnvironmentMode, so a repair can be limited to a developer machine.

Output for CI and AI Agents

The CLI output is the default, but --format=json produces a machine-readable report, and --format=github produces GitHub Actions annotations. Doctor rejects --fix with both of those, so a report meant for a machine never mutates the application.

There's a fourth format aimed at coding agents, and Doctor switches to it on its own when Laravel Agent Detector spots that it's running inside something like Claude Code or Cursor. It follows the Laravel PAO convention: one line of JSON, counts up front, and only the outcomes you can act on are itemised.

{"tool":"doctor","result":"failed","diagnostics":27,"failed":1,"warnings":1,"notices":0,"passed":19,"skipped":6,"issues":[{"name":".env file exists","status":"fail","summary":"The application does not have an environment file.","fix":"Run `cp .env.example .env`, then review the copied values.","fixable":true}]}

Which is the setup for the rest of the announcement:

Packages can register their own diagnostic checks, so a package with specific configuration requirements can plug directly into artisan doctor and surface its own health checks alongside the framework's. It's also a natural last step for AI coding agents: after making changes, an agent can run artisan doctor as a final sanity check before considering a task done.

Anything flagged fixable can be cleared by re-running with --fix, which applies the fixes, reruns the diagnostics, and appends the outcomes to the payload. Anything that comes back with an options map needs a choice --fix won't make on its own, and there the agent is meant to either follow the remediation text itself or hand the shortlist to a human. To see the format without an agent, run AI_AGENT=test php artisan doctor.

Doctor can also run without the Artisan command. Doctor::run() returns a DiagnosticReport, and only(), except(), bail(), and fixUsing() constrain the run programmatically.

Learn More

Laravel Doctor requires PHP 8.3 and Laravel 12 or 13, and is MIT licensed. The full documentation, including the diagnostic helpers in Laravel\Doctor\Support and the complete guide to writing your own checks, is on the Laravel Doctor GitHub repository.

Yannick Lyn Fatt photo

Staff Writer at Laravel News and Full stack web developer.

Sponsored

masteringlaravel logo
Laravel Code Review

Get expert guidance in a few days with a Laravel code review

Visit Laravel Code Review

The latest

View all →
PhpStorm 2026.2 Released image

PhpStorm 2026.2 Released

Read article
CPX: The Composer Package Executor for PHP image

CPX: The Composer Package Executor for PHP

Read article
Laravel AI SDK Adds Human-in-the-Loop Tool Approval image

Laravel AI SDK Adds Human-in-the-Loop Tool Approval

Read article
Pest 5 Released With Test Impact Analysis, Agent Verification, and Evals image

Pest 5 Released With Test Impact Analysis, Agent Verification, and Evals

Read article
Queue-SQL: Run Mass Deletes and Updates Across Parallel Queue Jobs image

Queue-SQL: Run Mass Deletes and Updates Across Parallel Queue Jobs

Read article
Blade Formatting in Laravel Pint image

Blade Formatting in Laravel Pint

Read article