> ## 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

> An introduction to laravel/doctor, the official Laravel package that diagnoses common configuration, environment, and infrastructure issues and automatically fixes the safe ones. Run it with php artisan doctor. Released July 28, 2026.

## Introduction

[laravel/doctor](https://github.com/laravel/doctor) is the official package for diagnosing common configuration, environment, and infrastructure issues in a Laravel application. v0.1.0 was released on July 28, 2026.

Each diagnostic is a single check. For example, "can Laravel write to the storage directory?" is checked and one of several statuses is reported. When a fix is safe and deterministic, an automatic fix is offered; when an issue can't be repaired automatically (a broken asset build, say), remediation steps are shown instead.

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

## Running it

After installation, the `doctor` Artisan command is registered.

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

When it finds a fixable problem, Doctor reports the issue and asks whether to apply 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]
```

Use the `--fix` option to apply fixes without confirmation.

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

The built-in fixes cover deterministic local repairs — creating `.env`, generating `APP_KEY`, disabling debug mode in production, adding `.env` to `.gitignore`, creating `storage:link`, and repairing write permissions on storage directories.

<Info>
  The fix functionality is available only in the CLI and agent output formats. In the JSON and GitHub report formats, `--fix` is rejected so that machine-readable reports don't modify the application.
</Info>

Use `--bail` to stop execution at the first diagnostic that fails or errors.

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

## Diagnostic statuses

Each diagnostic returns one of the following statuses.

| Status   | Meaning                                              | Affects exit code          |
| -------- | ---------------------------------------------------- | -------------------------- |
| `pass`   | Check succeeded and no issues were found             | No                         |
| `notice` | Information worth surfacing to the developer         | No                         |
| `warn`   | A potential issue that may or may not require action | Only with `--fail-on=warn` |
| `fail`   | A problem was found that should be resolved          | Yes                        |
| `skip`   | Does not apply to the current environment            | No                         |
| `error`  | An exception occurred while running the diagnostic   | Yes                        |

By default, the command exits with a failure status when there is a `fail` or `error`. Use `--fail-on=warn` to also fail on warnings, or `--fail-on=never` to only report issues.

## Selecting diagnostics

You can select or exclude diagnostics by class name, group, package, or a package wildcard.

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

php artisan doctor --only=StorageIsWritable

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

Publish the configuration file to configure persistent selections.

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

## Environment modes

The `sync` queue is a reasonable default during local development, but in production it means queued jobs run synchronously inside a web request. To make judgments like this, Doctor resolves your application into one of two modes: `local` or `production`.

| Mode         | Expected state                                                                                                                  |
| ------------ | ------------------------------------------------------------------------------------------------------------------------------- |
| `local`      | In development. Debug mode, the `sync` queue, and uncached bootstrap files are all normal.                                      |
| `production` | Serving real traffic. Debug mode is a security risk, the queue should run asynchronously, and bootstrap files should be cached. |

Laravel's standard environment names (`local`, `production`, `staging`) are recognized automatically. If you use other names, group them into modes in the configuration file.

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

## Built-in diagnostics

Doctor ships with a suite of built-in diagnostics that includes:

* **Environment** — `.env` presence, `APP_KEY`, PHP version, required extensions, timezone
* **Composer** — dependency install state, autoload optimization, auto-repair of `composer.lock`
* **Configuration** — whether the config files load and cache, required values for the drivers you have enabled
* **Database** — reachability of connections, existence of SQLite files, automatic application of pending migrations
* **Cache, queue, scheduler, session** — reachability of configured drivers, detection of the `sync` queue outside of production
* **Storage** — reachability of the default disk, write permissions on required directories, existence of `storage:link`
* **Security** — consistency between debug mode and environment, `.env` being present in `.gitignore`, audit of Composer dependencies

## Writing your own diagnostics

You can create your own diagnostic class by extending `Laravel\Doctor\Diagnostic` and implementing the `check()` method. You can also scaffold one with the `make:diagnostic` Artisan command.

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

Below is an example of a diagnostic that checks whether `APP_KEY` is configured and generates it automatically when it isn't.

```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;

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' => 'The application key is not configured.',
            'generated' => 'The application key was 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]);

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

When a fix has multiple sensible options, declare them with `fixOptions()`. The CLI will present them as a picklist, and the value that's chosen is passed to `fix()`.

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

A "don't fix" option is always appended to the picklist (the default is `Skip — leave unfixed`). When a phrase that keeps the current selection is clearer, specify a `decline` label.

```php theme={null}
->fixOptions(['file' => 'File'], decline: 'Keep Redis (repair it manually)');
```

### Diagnostic helpers

Many applications and packages end up writing the same kinds of checks over and over, so Doctor provides helpers in the `Laravel\Doctor\Support` namespace for common patterns.

The `Configured` helper reads configuration values defensively. Since a diagnostic must be able to inspect an app whose configuration is broken without throwing before it can report, these methods differ from the typed accessors on the config repository: they don't throw when they encounter unexpected types.

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

$connection = Configured::string('queue.default', 'database');

$missing = Configured::missing([
    'services.stripe.key',
    'services.stripe.secret',
]);
```

The `ActiveDrivers` helper resolves wrapper drivers — such as a default log channel of `stack` or a `failover` mailer — into the concrete channels or mailers that will actually be used.

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

$channels = ActiveDrivers::logChannels(Configured::string('logging.default', 'stack'));

$mailers = ActiveDrivers::mailers(Configured::string('mail.default', 'log'));
```

The `Details` helper formats evidence to attach to `withDetails()`. `Details::bullets()` renders a list of strings as bullets, `Details::failures()` renders keyed failure messages, and `Details::processOutput()` picks the most useful output stream from a completed process.

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

Details::bullets(['services.stripe.key', 'services.stripe.secret']);

Details::failures(['media' => 'The disk root is not writable.']);
```

Packages register diagnostics from a service provider with 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 which package provided each diagnostic.

```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 programmatically

You can also invoke `Doctor::run()` directly, without going through the Artisan command.

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

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

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

To also apply fixes when running programmatically, set `fixUsing`. The callback receives each failed diagnostic that provides a fix, and can return `false` to skip, `true` to apply the standard fix, or a fix option value to apply that specific choice. When a fix is applied, Doctor re-runs the diagnostic so it's reflected in the report.

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

$report->fixes();
```

## Output formats and AI agent support

By default Doctor produces a readable CLI report, but you can also choose JSON or the GitHub Actions annotation format.

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

php artisan doctor --format=github
```

When it detects that it's running inside an AI coding agent such as Claude Code or Cursor via [Laravel Agent Detector](https://github.com/laravel/agent-detector), the default becomes an agent-optimized format that follows the same convention as [Laravel PAO](https://github.com/laravel/pao).

```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}]}
```

Any issue with `fixable: true` can be repaired by re-running with `--fix`. To try this format outside of an agent, run `AI_AGENT=test php artisan doctor`.

## Wrap-up

`laravel/doctor` lets you quickly surface configuration, environment, and infrastructure problems with a single `php artisan doctor` run. It plays nicely with AI coding agents by producing output in the same convention as Laravel PAO, making it worth considering for CI/CD or automated agent-driven repair workflows.

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


## Related topics

- [Tools](/en/packages/laravel-copilot-sdk/tools.md)
- [Laravel and AI development](/en/ai.md)
- [Laravel AI SDK](/en/ai-sdk.md)
- [Laravel MCP](/en/mcp.md)
- [Request lifecycle](/en/lifecycle.md)
