How to Set Up Xdebug with Laravel Sail: A Complete Guide

Dr. Adam Nielsen
7 min readSep 10, 2024

--

Xdebug is a powerful tool for debugging PHP applications, offering more advanced features compared to basic debugging methods like dd() or var_dump(). With Xdebug, you can set breakpoints, inspect variables, step through code execution, and gain deep insight into the behavior of your application—all in real-time. In a Dockerized environment like Laravel Sail, setting up Xdebug can seem challenging, but this guide will walk you through the process, from basic setup to more advanced customizations.

This article assumes you are running Laravel with Sail

1. Setting Up Xdebug in Laravel Sail

Out of the box, Laravel Sail comes with Xdebug pre-installed, but it’s turned off by default. To enable Xdebug, you just need to modify the .env file.

Step 0: Fix php.ini

According to the docs modify the .env file is enough.

However, it seems that this part of the docs is currently plain wrong. The SAIL_XDEBUG_MODE environment variable doesn't take effect out of the box because the default Sail configuration doesn't dynamically apply the variable in the container's php.ini file. This has been an unresolved issue since 2022 (GitHub issue #357).

To ensure that SAIL_XDEBUG_MODE works as intended, you need to publish and customize your php.ini file.

Run the following command to publish the Sail Docker configuration:

php artisan sail:publish

After publishing, locate the php.ini file in the docker directory. Check your docker-compose.yml for the PHP version used in your Sail container (e.g., 8.2).

Go then to ./docker/8.2/php.ini and add this

Now changes to the variable SAIL_XDEBUG_MODE does actually take effect.

After this change, you need to rebuild your container

./vendor/bin/sail down
./vendor/bin/sail build --no-cache

Step 1: Enable Xdebug

Open your .env file and add or modify the following line to enable Xdebug:

SAIL_XDEBUG_MODE=debug

This will enable Xdebug in debug mode for your Sail environment.

By default, your docker-compose.yml file should look like this:

Meaning if you don’t specify SAIL_XDEBUG_MODE xDebug is turned off.

Step 2: Rebuild and Restart Sail

Once you’ve updated your .env file, you need to restart your Sail container (rebuild is not needed, restart is enough!):

./vendor/bin/sail down
./vendor/bin/sail up

This will apply the changes, and Xdebug should now be active.

2. Verifying Xdebug is Running

To verify that Xdebug is running, you can create a simple route in your Laravel application to show the current PHP configuration:

Route::get('/xdebug', function () { xdebug_info(); });

Visit /xdebug in your browser, if you see this, it is working. It shows you also all configuration settings.

Alternatively, you can verify Xdebug from the command line inside the Sail container:

./vendor/bin/sail shell
php -i | grep xdebug

This should output details about Xdebug’s configuration and confirm that it’s running.

Validate the configuration, xdebug.mode should be set to debug :

And client_host and client_port should look like this:

If you running an old Docker version pre 20.10, you have to assign a static ip to the client host, as host.docker.internal is only supported since Docker 20.10 (This setting works for Ubuntu aswell!).

3. Configuring PhpStorm for Xdebug

Once Xdebug is running, the next step is to configure PhpStorm to listen for Xdebug connections.

Step 1: Set the Debugger Port

Go to Settings > Languages & Frameworks > PHP > Debug and set the debug port to 9003 (the default for Xdebug 3).

Step 2: Set Up a PHP Server

In Settings > PHP > Servers, add a new server configuration:

  • Name: 0.0.0.0
  • Host: 0.0.0.0
  • Port: 80
  • Use path mappings: Check this box and map the server path (usually/var/www/html) to your local project directory.

Step 3: Install the Xdebug Helper Browser Extension

Since Laravel Sail uses start_with_request=default by default, you'll need to manually trigger Xdebug when making requests. One of the easiest ways to do this is by using the Xdebug Helper browser extension:

  1. Install the Xdebug Helper extension for your browser (available for Chrome and Firefox).
  2. When you’re ready to debug, enable “Debug” mode in the extension before making a request, and Xdebug will start when you load the page.

Note: If you want to trigger Xdebug without the browser extension (by using URL parameters or modifying the configuration), see Step 5 for more details.

Step 4: Listen for Xdebug Connections

Click the “Start Listening for PHP Debug Connections” button (a bug icon in the top right corner) to enable PhpStorm to listen for incoming Xdebug connections.

4. Basic Debugging in Laravel

With Xdebug running and PhpStorm set up, you can now start debugging your Laravel application.

  • Set breakpoints in your code by clicking on the line number in PhpStorm.
  • Reload the page in your browser, and PhpStorm should catch the breakpoint and pause execution.

If Xdebug doesn’t stop at your breakpoints, revisit the settings from Step 2 and Step 3 to ensure the port and server configuration are correct.

5. Still not working? Try those settings:

Key PhpStorm Settings for Xdebug Debugging

To ensure a smooth debugging experience in PhpStorm, you’ll want to configure two important settings under Settings > PHP > Debug:

  1. Break at First Line in PHP Scripts:
  • When to enable: This option causes Xdebug to break at the first line of every PHP script automatically. Enable it if you’re troubleshooting from the very beginning of your code. This makes sure xdebugs triggers, even if it never reases teh code where you set the breakpoint.
  • When to disable: Disabling this option allows Xdebug to only stop at specific breakpoints you’ve set. This is useful when you are sure xdebug works.
  1. You can toggle this setting under Settings > PHP > Debug > Break at first line in PHP scripts.
  2. Ignore External Connections Through Unregistered Server Configurations:
  • When to enable: This option prevents Xdebug from catching external connections when there is no registered server configuration in PhpStorm. This is useful for avoiding confusion when PhpStorm encounters requests that aren’t mapped to a server. Mabe you need to use something else instead of 0.0.0.0 ?
  • When to disable: If you are sure xDebug is setup correctly, you may disable it.
  1. You can find this option in Settings > PHP > Debug as Ignore external connections through unregistered server configurations.
  • Tip: During initial setup and testing, it can be helpful to leave “Break at first line in PHP scripts” checked and “Ignore external connections” unchecked.

6. Customizing Xdebug Behavior: start_with_request=default vs. yes

By default, Laravel Sail configures Xdebug with start_with_request=default, meaning Xdebug only starts a debug session when explicitly triggered (e.g., through a browser extension like Xdebug Helper). However, you can customize Xdebug to automatically start on every request by changing the start_with_request setting.

Understanding the Default Behavior (start_with_request=default)

  • How it works: Xdebug waits for an explicit trigger (e.g., the Xdebug Helper browser extension or the XDEBUG_SESSION_START URL parameter) before starting a debug session. This setup improves performance by avoiding debugging overhead on every request.

Switching to start_with_request=yes

If you want Xdebug to start debugging automatically on every request (without needing the browser extension or URL parameter), you can switch to start_with_request=yes but be aware, this may slow down your machine performance.

How to Change the Setting:

  1. Publish Sail’s Docker Configuration:
./vendor/bin/sail artisan sail:publish

2. Update the php.ini File: In the published configuration folder (docker/8.2/php.ini), update the Xdebug settings:

[XDebug]
zend_extension = xdebug.so
xdebug.mode = debug
xdebug.start_with_request = yes
xdebug.discover_client_host = true
xdebug.idekey = PHPSTORM
xdebug.client_host = host.docker.internal
xdebug.client_port = 9003

3. Rebuild and Restart Sail:

With this setting, Xdebug will automatically start a debug session for every request, which can simplify debugging but may slightly reduce performance during development.

Note: If you prefer the default behavior and want to selectively trigger debugging using the Xdebug Helper browser extension or URL parameters, you can leave start_with_request=default unchanged.

--

--

Dr. Adam Nielsen
Dr. Adam Nielsen

Written by Dr. Adam Nielsen

PHD in math. and Laravel / Vue Full-Stack-Developer

Responses (2)