Setting up xdebug with swoole could be a bit of a hustle especially if application is containerized and you are running swoole and xdebug in a docker container but your IDE is on the host. Here’s what worked for me. Here I’m using hyperf framework, but I think issues and instructions should be similar for other swoole based frameworks (mezzio, resonance etc). Swoole 5.0.1 + PHP 8.1 natively support xdebug, so there is no need to use old dedicated swoole debugger (no need for sdebug/yasd).
Here is what worked for me:
1. Make sure your Dockerfile has swoole and xdebug installed, many ways to do that – this is just a simplistic pecl example:
RUN pecl install xdebug-3.4.0
RUN pecl install \
--configureoptions 'enable-openssl="yes" enable-swoole-curl="yes"' swoole-6.0.2
2. docker container swoole.ini should look like this, most important is to add swoole.enable_fiber_mock
=On:
; Configuration for Swoole
; priority=30
extension=swoole
swoole.enable_fiber_mock = On
3. Set number of workers to 1 for xdebug to work. This could be optional – try it without reducing workers first. Here I’m using hyperf framework and it’s server.php configuration:
// For xdebug - we have to make sure to specify number of workers as 1
Constant::OPTION_WORKER_NUM => APP_ENV =='sandbox' ? 1 : swoole_cpu_num(),
Constant::OPTION_TASK_WORKER_NUM => APP_ENV =='sandbox' ? 4 : swoole_cpu_num() * 2,
4. xdebug configuration – docker container xdebug.ini. You need to replace the YOUR_HOST_IP with your host ip.
I do replacement automatically in my Dockerfile but you could also just set it manually.
zend_extension=xdebug
xdebug.mode=debug
xdebug.client_port=9006
; trigger for some reason never worked for me, so I had to use "always"
;xdebug.start_with_request=trigger
xdebug.start_with_request=yes
xdebug.idekey = VSCODE
;this is most important with docker debugging.
xdebug.client_host=YOUR_HOST_IP
xdebug.discover_client_host = true
5. vscode debugger configuration (I’m use windsurf for coding, but either vscode, or cursor should work the same way)- add this code to ./.vscode/launch.json
file. Note that port=9006 has to be the same you used in xdebug.ini.
If you have multiple PHP apps you are working on with xdebug, you want to use different xdebug port for every PHP app if you’d like to debug them simultaneously. /app/backend/
path -> is wherever you mounted your PHP code in a docker container.
{
"version": "0.2.0",
"configurations": [
{
"name": "Xdebug in docker",
"type": "php",
"request": "launch",
"port": 9006,
"pathMappings": {
"/app/backend/": "${workspaceFolder}/backend/",
}
}
]
}
6. Launch xdebug listener from vscode/windsurf “run and debug” menu:
VERY IMPORTANT: start xdebug listener before you launch your swoole application!!!
I think PHP app will only try to connect to your xdebug listener only ONCE on PHP application boot and if xdebug is not listening -> xdebug debugger will just not work.

7. Launch your PHP application.
Note – This is very important that you start xdebug listener before you start you PHP swoole application. I don’t believe swoole application would would try reconnecting to xdebug after PHP swoole application already started. (Let me know if this is something that could be configured).
8. Set code breakpoints in your IDE (just double click) and reload browser page (whatever api or SSR endpoint you are working on) – you browser page loading will freeze and you should see full app state in your vscode (I use windsurf for coding here in this picture).
Use that little debug panel in the middle to continue execution or step into/over/out your code. Isn’t this cool?

Have fun with xdebug, hyperf and swoole. 👌