> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Laravel Doctor — Application Diagnostics Tool

> Introducing laravel/doctor, the official Laravel package that diagnoses common configuration, environment, and infrastructure problems and auto-fixes safe issues. Run php artisan doctor. Released July 28, 2026.

## Introduction

[laravel/doctor](https://github.com/laravel/doctor) is an official Laravel package that diagnoses common configuration, environment, and infrastructure problems in your application. v0.1.0 was released on July 28, 2026.

Each diagnostic is a single check — it inspects one thing, such as whether Laravel can write to its storage directories, and reports one of several statuses. When the repair is safe and deterministic, a diagnostic may also offer a fix. Issues that cannot be repaired safely, such as a failed asset build, are reported with remediation steps instead.

```bash theme={null}
composer require laravel/doctor --dev
```

## Running Doctor

Once installed, the package registers the `doctor` Artisan command:

```bash theme={null}
php artisan doctor
```

When a failing diagnostic can be fixed, Doctor reports the problem and prompts before applying the fix:

```text theme={null}
Storage is writable: The application cannot write to every required storage directory.

 Make the storage directories writable? (yes/no) [yes]
```

Some fixes offer a choice of repairs instead of a yes/no confirmation. When the default cache store is unreachable, for example, Doctor presents a select list of configured stores that actually work, along with an option to keep the current store and repair it manually.

To apply all available fixes without prompting, pass the `--fix` option:

```bash theme={null}
php artisan doctor --fix
```

First-party fixes cover deterministic local repairs such as creating a missing `.env`, generating `APP_KEY`, disabling production debug mode, adding `.env` to `.gitignore`, creating the public storage link, and repairing writable storage directories.

<Info>
  Fixes are only available with the CLI and agent output formats. Doctor rejects `--fix` with JSON and GitHub report formats so machine-readable reports never mutate the application.
</Info>

Use `--bail` to stop after the first diagnostic that fails or errors:

```bash theme={null}
php artisan doctor --bail
```

## Diagnostic Statuses

Every diagnostic returns one of the following statuses:

| Status   | Meaning                                                 | Affects exit code          |
| -------- | ------------------------------------------------------- | -------------------------- |
| `pass`   | The check succeeded and nothing is wrong.               | No                         |
| `notice` | Informational context worth surfacing to the developer. | No                         |
| `warn`   | A potential problem that may not require action.        | Only with `--fail-on=warn` |
| `fail`   | The check found a problem that should be resolved.      | Yes                        |
| `skip`   | The check did not apply to the current environment.     | No                         |
| `error`  | The diagnostic threw an exception while running.        | Yes                        |

By default, the command exits with a failing status when a diagnostic fails or errors. Use `--fail-on=warn` to also fail on warnings, or `--fail-on=never` when Doctor should only report issues.

## Selecting Diagnostics

Diagnostics may be selected or excluded by class name, group, package, or package wildcard. Multiple values may be passed by repeating the option or separating values with commas.

```bash theme={null}
php artisan doctor --only=storage

php artisan doctor --only=StorageIsWritable

php artisan doctor --only=vendor/package

php artisan doctor --except=laravel/*
```

To configure persistent diagnostic selection, publish Doctor's configuration file:

```bash theme={null}
php artisan vendor:publish --tag=doctor-config
```

## Environment Modes

Some facts about an application cannot be judged on their own. A `sync` queue connection is sensible on a developer's machine, but in production it means queued jobs silently run inside web requests. To judge these diagnostics, Doctor resolves the application to one of two modes:

| Mode         | Expectations                                                                                                             |
| ------------ | ------------------------------------------------------------------------------------------------------------------------ |
| `local`      | Active development. Debug mode, `sync` queues, and uncached bootstrap files are normal.                                  |
| `production` | Serving real traffic. Debug mode is a security risk, queues should run asynchronously, bootstrap files should be cached. |

The mode changes the verdict, not just the message. Missing bootstrap caches warn in production but pass locally.

Doctor recognizes Laravel's conventional `local`, `production`, and `staging` environment names out of the box. For custom names, group them in the configuration file:

```php theme={null}
'environments' => [
    'local' => ['local', 'dev'],
    'production' => ['production', 'staging', 'qa'],
],
```

Any environment not listed is treated as `production`, so unfamiliar environments are held to the strictest expectations rather than quietly excused.

## Default Diagnostics

Doctor ships with a focused suite of diagnostics:

* **Environment** — `.env` presence, `APP_KEY`, PHP version, required extensions, and timezone.
* **Composer** — dependencies installed, autoload optimization, repairable `composer.lock` problems.
* **Configuration** — config files can be loaded and cached, required values are set, bootstrap cache state matches the environment.
* **Database** — default connection is reachable, SQLite file exists when needed, pending migrations can be applied in local environments.
* **Cache, queue, scheduler, and session** — configured drivers are reachable, `sync` queues are flagged outside local environments, scheduled tasks are surfaced as a notice.
* **Storage** — default disk is reachable, required directories are writable, `storage:link` exists when expected.
* **Security** — debug mode matches the environment, `.env` is gitignored, Composer dependencies are audited.

## Creating Diagnostics

A diagnostic extends `Laravel\Doctor\Diagnostic` and implements a `check()` method returning a `DiagnosticResult`. Scaffold one with the `make:diagnostic` Artisan command:

```bash theme={null}
php artisan make:diagnostic HorizonIsRunning --fixable
```

The following diagnostic checks whether the application key is set and implements `Fixable` to generate it automatically:

```php theme={null}
namespace App\Doctor\Diagnostics;

use Illuminate\Support\Facades\Artisan;
use Laravel\Doctor\Contracts\Fixable;
use Laravel\Doctor\Diagnostic;
use Laravel\Doctor\EnvironmentMode;
use Laravel\Doctor\Results\DiagnosticResult;
use Laravel\Doctor\Results\FixResult;
use Laravel\Doctor\Results\Link;
use Laravel\Doctor\Results\Message;

class ApplicationKeyIsSet extends Diagnostic implements Fixable
{
    public string $name = 'App key is set';

    public string $group = 'environment';

    protected function messages(): array
    {
        return [
            'configured' => 'The application key is configured.',

            'missing' => Message::make(
                summary: 'The application key is not configured.',
                remediation: 'Generate an application key with `php artisan key:generate`.',
                confirmation: 'Generate an application key using `php artisan key:generate`?',
            )->link(Link::docs('encryption')),

            'generated' => 'The application key was generated.',

            'generation-failed' => 'The application key could not be generated.',
        ];
    }

    public function check(): DiagnosticResult
    {
        $key = config('app.key');

        if (is_string($key) && trim($key) !== '') {
            return $this->pass('configured');
        }

        return $this->fail('missing')->fixable(EnvironmentMode::Local);
    }

    public function fix(DiagnosticResult $result): FixResult
    {
        Artisan::call('key:generate', ['--force' => true]);

        $key = config('app.key');

        if (! is_string($key) || trim($key) === '') {
            return $this->fixFailed('generation-failed')
                ->withDetails(trim(Artisan::output()));
        }

        return $this->fixed('generated');
    }
}
```

When a failure has several valid repairs, declare the choices with `fixOptions()`. The CLI renders them as a select list, and the chosen value is passed to `fix()`:

```php theme={null}
return $this->fail('unreachable')
    ->fixable(EnvironmentMode::Local)
    ->fixOptions(['file' => 'File', 'redis' => 'Redis']);
```

Packages register diagnostics from their service providers using the same API:

```php theme={null}
use Laravel\Doctor\Facades\Doctor;
use Vendor\Package\Diagnostics\HorizonIsRunning;

public function boot(): void
{
    Doctor::diagnostic(HorizonIsRunning::class);
}
```

Reports show each diagnostic's source package next to its name:

```text theme={null}
[fail] Storage is writable (laravel/doctor): The application cannot write to every required storage directory.
[warn] Horizon is running (laravel/horizon): Horizon is not currently running.
```

## Running Doctor Programmatically

Call `Doctor::run()` without the Artisan command to get a `DiagnosticReport`:

```php theme={null}
use Laravel\Doctor\Facades\Doctor;

$report = Doctor::only('security')
    ->except(SomeDiagnostic::class)
    ->run();

if ($report->hasFailures()) {
    // ...
}
```

To apply fixes as part of a programmatic run, configure the run with `fixUsing`:

```php theme={null}
$report = Doctor::fixUsing(
    fn ($outcome) => $outcome->fixRequiresOption() ? false : true,
)->run();

$report->fixes();
```

## Output Formats and AI Agent Support

Doctor renders readable CLI output by default. JSON and GitHub Actions annotations are also available:

```bash theme={null}
php artisan doctor --format=json

php artisan doctor --format=github
```

When Doctor detects it is running inside an AI coding agent such as Claude Code or Cursor — using [Laravel Agent Detector](https://github.com/laravel/agent-detector) — it defaults to an agent-optimized format following the [Laravel PAO](https://github.com/laravel/pao) convention:

```json theme={null}
{"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}]}
```

Issues marked `fixable` may be fixed by re-running Doctor with `--fix`. An explicit `--format` option always overrides detection. To preview agent output outside an agent:

```bash theme={null}
AI_AGENT=test php artisan doctor
```

## Summary

`laravel/doctor` lets you quickly surface configuration, environment, and infrastructure problems with a single `php artisan doctor` command. Its deep integration with AI coding agents and the Laravel PAO convention makes it a natural fit for CI/CD pipelines and agent-driven auto-repair workflows.

<Card title="laravel/doctor repository" icon="github" href="https://github.com/laravel/doctor">
  Source code and latest updates.
</Card>


## Related topics

- [Tools](/en/packages/laravel-copilot-sdk/tools.md)
- [Laravel LSP — extending IDE features via the Language Server Protocol](/en/blog/laravel-lsp-introduction.md)
- [Laravel and AI development](/en/ai.md)
- [Laravel AI SDK](/en/ai-sdk.md)
- [Laravel MCP](/en/mcp.md)
