Skip to content

feat: xdebug configurability overhaul#247

Open
AaronFeledy wants to merge 21 commits intomainfrom
feature/xdebug-configurability
Open

feat: xdebug configurability overhaul#247
AaronFeledy wants to merge 21 commits intomainfrom
feature/xdebug-configurability

Conversation

@AaronFeledy
Copy link
Member

@AaronFeledy AaronFeledy commented Mar 17, 2026

Summary

Complete overhaul of xdebug support in the PHP plugin, addressing the #1 source of developer pain.

Phase 1: Fix broken stuff

Phase 2: Built-in lando xdebug toggle

  • New scripts/xdebug.sh — POSIX /bin/sh compatible toggle script
  • lando xdebug debug / lando xdebug off / lando xdebug debug,develop — no rebuild required
  • lando xdebug (no args) shows status: loaded state, mode, client host, client port
  • Auto-detects apache vs php-fpm for reload
  • Registered as default tooling (user overrides take precedence)
  • Addresses Allow faster xdebug on/off toggling lando#1668 (open since 2019, 36+ thumbs up)

Phase 3: Configurable xdebug object

  • New object format in .lando.yml:
    xdebug:
      mode: debug
      start_with_request: yes
      client_host: auto
      client_port: 9003
      log: /tmp/xdebug.log
      idekey: LANDO
      config:
        max_nesting_level: 256
  • Strict backward compatibility: true, false, and string formats still work identically
  • Generates dedicated yyy-lando-xdebug.ini (loads after defaults, before user custom)
  • Runtime toggle (zzz-lando-xdebug.ini) always takes precedence

Phase 4: Developer experience

  • lando info now includes xdebug configuration (mode, client_host, client_port, start_with_request)

Tests

  • Comprehensive leia tests covering all phases (backward compat, toggle, config object, pass-through, info output)
  • Unit tests for normalizeXdebugConfig() and generateXdebugIni() (13 passing)

Related issues


Note

Medium Risk
Moderate risk because it changes how Xdebug is configured/enabled at build/runtime (new ini generation, new defaults, new tooling), which can affect developer debugging behavior across PHP versions.

Overview
Overhauls Xdebug configuration for the PHP service by generating a dedicated yyy-lando-xdebug.ini from .lando.yml (including a new object-style config while keeping boolean/string backward compatibility) and wiring the result into the container via volume mount and XDEBUG_CONFIG.

Adds built-in lando xdebug tooling via a new scripts/xdebug.sh that can toggle xdebug.mode at runtime (writing zzz-lando-xdebug.ini and reloading Apache/PHP-FPM) without requiring lando rebuild, and surfaces key Xdebug settings in lando info output.

Cleans up legacy Xdebug 2 ini settings from the default php.ini, updates examples/docs/tests accordingly, and bumps package-lock.json version metadata.

Written by Cursor Bugbot for commit 89a5d67. This will update automatically on new commits. Configure here.

@netlify
Copy link

netlify bot commented Mar 17, 2026

Deploy Preview for lando-php ready!

Name Link
🔨 Latest commit 89a5d67
🔍 Latest deploy log https://app.netlify.com/projects/lando-php/deploys/69ba2fb451b825000866abac
😎 Deploy Preview https://deploy-preview-247--lando-php.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 81 (🔴 down 8 from production)
Accessibility: 98 (no change from production)
Best Practices: 100 (no change from production)
SEO: 100 (no change from production)
PWA: -
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Autofix Details

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: XDEBUG_MODE env var silently defeats runtime toggle
    • Removed XDEBUG_MODE environment variable from line 315 to allow INI-based toggle script to control xdebug mode without env var override.
  • ✅ Fixed: XDEBUG_CONFIG overrides user-specified client_host setting
    • Updated xdebugConfig() function to accept and use the user's normalized configuration values instead of hardcoded values for client_host and log settings.

Create PR

Or push these changes by commenting:

@cursor push 8dd8b2ff7d
Preview (8dd8b2ff7d)
diff --git a/builders/php.js b/builders/php.js
--- a/builders/php.js
+++ b/builders/php.js
@@ -51,15 +51,15 @@
   version: options.via.split(':')[1],
 });
 
-const xdebugConfig = phpSemver => {
+const xdebugConfig = (phpSemver, normalizedConfig) => {
   const config = [
-    'client_host=host.lando.internal',
+    `client_host=${normalizedConfig.client_host}`,
     'discover_client_host=1',
-    'log=/tmp/xdebug.log',
+    `log=${normalizedConfig.log === false ? '' : normalizedConfig.log}`,
   ];
 
   if (phpSemver && semver.lt(phpSemver, '7.2.0')) {
-    config.push('remote_enable=true', 'remote_host=host.lando.internal');
+    config.push('remote_enable=true', `remote_host=${normalizedConfig.client_host}`);
   }
 
   return config.join(' ');
@@ -311,8 +311,7 @@
         environment: _.merge({}, options.environment, {
           PATH: options.path.join(':'),
           LANDO_WEBROOT: `/app/${options.webroot}`,
-          XDEBUG_CONFIG: xdebugConfig(phpSemver),
-          XDEBUG_MODE: options._xdebugConfig.mode,
+          XDEBUG_CONFIG: xdebugConfig(phpSemver, options._xdebugConfig),
         }),
         networks: (_.startsWith(options.via, 'nginx')) ? {default: {aliases: ['fpm']}} : {default: {}},
         ports: (_.startsWith(options.via, 'apache') && options.version !== 'custom') ? ['80'] : [],

@AaronFeledy
Copy link
Member Author

@cursor push 8dd8b2f

- Remove XDEBUG_MODE env var to allow INI-based toggle to work
- Update xdebugConfig() to use user's normalized config values instead of hardcoded values
- Fixes client_host and other settings being overridden by XDEBUG_CONFIG env var

Applied via @cursor push command
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Hardcoded max_nesting_level duplicates config pass-through entries
    • Moved max_nesting_level default (512) to config defaults in normalizeXdebugConfig, eliminating duplicate ini entries.

Create PR

Or push these changes by commenting:

@cursor push bc1017f136
Preview (bc1017f136)
diff --git a/builders/php.js b/builders/php.js
--- a/builders/php.js
+++ b/builders/php.js
@@ -78,7 +78,9 @@
     client_port: 9003,
     log: '/tmp/xdebug.log',
     idekey: '',
-    config: {},
+    config: {
+      max_nesting_level: 512,
+    },
   };
 
   if (xdebug === true) return _.merge({}, defaults, {mode: 'debug'});
@@ -104,7 +106,6 @@
   const ini = [
     '; Generated by Lando PHP plugin',
     `xdebug.mode = ${config.mode}`,
-    `xdebug.max_nesting_level = 512`,
     `xdebug.start_with_request = ${config.start_with_request}`,
     `xdebug.client_host = ${config.client_host}`,
     `xdebug.client_port = ${config.client_port}`,

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Test expects XDEBUG_MODE env var that code no longer sets
    • Updated the test to check xdebug mode via php -i | grep "xdebug.mode" instead of checking the XDEBUG_MODE environment variable that is no longer set.

Create PR

Or push these changes by commenting:

@cursor push e62e7d0f9c
Preview (e62e7d0f9c)
diff --git a/examples/xdebug/README.md b/examples/xdebug/README.md
--- a/examples/xdebug/README.md
+++ b/examples/xdebug/README.md
@@ -52,7 +52,7 @@
 lando exec xdebug-true -- php -i | grep "xdebug.mode" | grep debug
 
 # Should set mode from string (backward compat)
-lando exec xdebug-string -- env | grep XDEBUG_MODE | grep "debug,develop"
+lando exec xdebug-string -- php -i | grep "xdebug.mode" | grep "debug,develop"
 
 # Should set mode from object config
 lando exec xdebug-object -- php -i | grep "xdebug.mode" | grep debug

@AaronFeledy
Copy link
Member Author

@cursor push e62e7d0

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Disabled xdebug changes from falsy to truthy value
    • Changed line 287 to preserve false (falsy) when xdebug mode is 'off' instead of setting it to the string 'off' (truthy), maintaining backward compatibility for truthiness checks.

Create PR

Or push these changes by commenting:

@cursor push f7e206bb7a
Preview (f7e206bb7a)
diff --git a/builders/php.js b/builders/php.js
--- a/builders/php.js
+++ b/builders/php.js
@@ -284,7 +284,7 @@
       }
 
       options._xdebugConfig = normalizeXdebugConfig(options.xdebug);
-      options.xdebug = options._xdebugConfig.mode;
+      options.xdebug = options._xdebugConfig.mode !== 'off' ? options._xdebugConfig.mode : false;
       if (options._xdebugConfig.mode !== 'off') {
         const xdebugFile = path.join(options.confDest, options.defaultFiles.xdebug);
         fs.mkdirSync(options.confDest, {recursive: true});

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Custom xdebug settings lost when toggling from off
    • The yyy-lando-xdebug.ini file is now always generated with all custom settings regardless of mode, ensuring configuration persists when toggling xdebug on.

Create PR

Or push these changes by commenting:

@cursor push bdb96bca48
Preview (bdb96bca48)
diff --git a/builders/php.js b/builders/php.js
--- a/builders/php.js
+++ b/builders/php.js
@@ -285,12 +285,10 @@
 
       options._xdebugConfig = normalizeXdebugConfig(options.xdebug);
       options.xdebug = options._xdebugConfig.mode;
-      if (options._xdebugConfig.mode !== 'off') {
-        const xdebugFile = path.join(options.confDest, options.defaultFiles.xdebug);
-        fs.mkdirSync(options.confDest, {recursive: true});
-        fs.writeFileSync(xdebugFile, generateXdebugIni(options._xdebugConfig));
-        options.volumes.push(`${xdebugFile}:${options.remoteFiles.xdebug}`);
-      }
+      const xdebugFile = path.join(options.confDest, options.defaultFiles.xdebug);
+      fs.mkdirSync(options.confDest, {recursive: true});
+      fs.writeFileSync(xdebugFile, generateXdebugIni(options._xdebugConfig));
+      options.volumes.push(`${xdebugFile}:${options.remoteFiles.xdebug}`);
 
       options._app.config.tooling = options._app.config.tooling || {};
       if (_.get(options, '_app.config.tooling.xdebug') === undefined) {

@AaronFeledy
Copy link
Member Author

@cursor push bdb96bc

cursoragent and others added 2 commits March 18, 2026 04:11
When xdebug mode defaults to 'off', custom settings like client_port,
start_with_request, and idekey were not being persisted to the ini file.
This caused settings to be lost when toggling xdebug on later.

Now the yyy-lando-xdebug.ini file is always created with all settings,
regardless of mode, ensuring custom configuration persists through
xdebug toggles.

Applied via @cursor push command
- Fix config pass-through producing duplicate ini directives by using
  an ordered Map instead of array appending. Pass-through values now
  override defaults naturally without duplicates.
- Add try/catch around sync fs writes for xdebug ini file to surface
  meaningful error messages on failure.
- Add comments explaining the yyy/zzz ini layering strategy in both
  builders/php.js and scripts/xdebug.sh.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

XDEBUG 3 complains about xdebug.remote_autostart = 1 in /usr/local/etc/php/conf.d/xxx-lando-default.ini

2 participants