Hi internals,
I'd like to start the discussion on a new RFC: https://wiki.php.net/rfc/single-binary-cli-fpm
It proposes a new --enable-cli-fpm build option that links the FPM SAPI into the php executable. A combined php binary runs FPM when its first argument is --fpm, or when it is invoked under a name starting with php-fpm (e.g. a php-fpm symlink to php). Everything else is the CLI, unchanged. The standalone php-fpm executable is still built.
php script.php # CLI, as today
php --fpm --nodaemonize -y /etc/php-fpm.conf # FPM
ln -s php php-fpm
./php-fpm --nodaemonize -y /etc/php-fpm.conf # FPM, through a symlink
The motivation is that the two executables share almost all their code. I did some measurements with Bref on AWS Lambda to illustrate its usefulness for this specific system. Shipping one binary instead of two:
- removes one of the two ~26 MB executables from the runtime (leaving more room under the 250 MB limit for application code)
- cuts the cold start of a minimal FPM application by 70 ms (-25%), because FPM no longer loads a second copy of the engine right after the CLI loaded it
It makes a difference on AWS Lambda, it might also help on other systems where boot speed (autoscaling, serverless, etc.) or disk size is important.
And from a simplicity perspective I like the idea of having a single binary with FPM "built-in".
There's a secondary vote on enabling the option by default, as Marc suggested when I requested RFC karma.
I'd especially welcome feedback from packagers:
- Would you consider shipping
php-fpmas a symlink to a combinedphpbinary, with the FPM package keeping only the configuration and service files? - Should this stay opt-in, or be enabled by default?
The implementation is at https://github.com/php/php-src/pull/23558 (thanks Jakub and Marc for the reviews so far).
Thanks,
Matthieu Napoli
Hi
I'd like to start the discussion on a new RFC:
https://wiki.php.net/rfc/single-binary-cli-fpm
Thank you for the RFC. The proposal makes sense to me and from what I
understand there are basically no drawbacks to combining the two
binaries into one. I only have one concern regarding:
PHP_BINARYin FPM mode is the path of the combined php executable,
where it is the path of php-fpm today (a symlink is resolved to its
target). Unlike php-fpm, that executable can also run CLI scripts.
This means scripts running in a FPM web context and relying on
PHP_BINARY cannot spawn fresh FPM instances (for whatever reason),
without adding a --fpm flag themselves. However I don't think it is
possible to determine from PHP itself if the binary is a combined binary
or not. Should we have some PHP_FPM_IN_CLI constant or similar that
allows scripts to make that distinction.
The RFC also notes that the standalone PHP FPM binary will remain an
option. Is there any reason to keep support for that, except for
backward compatibility? I think we should strongly encourage folks to
ship PHP as a “single binary” CLI+FPM distribution. Or just CLI where
FPM is not required and the extra dependencies should go away. But just
FPM doesn't feel like a reasonable use case.
Best regards
Tim Düsterhus
This means scripts running in a FPM web context and relying on
PHP_BINARYcannot spawn fresh FPM instances (for whatever reason),
without adding a--fpmflag themselves.
Right, though starting a new FPM master from a script running inside FPM already seems rare to me, and such code would need to know the FPM setup (config file, etc.).
The opposite case is more common though (scripts in FPM that use PHP_BINARY to run CLI commands. The RFC would make that simpler.
If there is a real need, I see two simpler options:
php-fpmcould ignore--fpmso thatPHP_BINARY --fpm ...always work- if embedding FPM is the default, then
PHP_BINARY --fpm ...should work in most cases then
The RFC also notes that the standalone PHP FPM binary will remain an option. Is there any reason to keep support for that, except for backward compatibility?
No. I'd find this preferable to drop php-fpm in a separate step/RFC since that's a fairly big breaking change for packagers.
Matthieu
Hi
If there is a real need, I see two simpler options:
I'm not sure there is a real need, but it's a theoretical breaking
change with no way to work around from what I can tell. A hypothetical
use case could be “spawn customer-specific FPM pools from a PHP-based
control panel”, for example for some playground.
php-fpmcould ignore--fpmso thatPHP_BINARY --fpm ...always
work
That suggestion makes sense to me and would resolve the above: php-fpm
would just mean php --fpm and php --fpm --fpm would then just be a
duplicate --fpm flag. Ordering matters with regard to --fpm, but
that seems obvious enough to explain.
The RFC also notes that the standalone PHP FPM binary will remain an
option. Is there any reason to keep support for that, except for
backward compatibility?No. I'd find this preferable to drop
php-fpmin a separate step/RFC
since that's a fairly big breaking change for packagers.
Should the “this” in “this preferable” mean “it” instead? The “this” in
your phrasing could refer to my suggestion, which doesn't make sense to
me.
In any case, packagers already need to deal with all kinds of packaging
changes (e.g. OPcache becoming non-optional in PHP 8.5). I'm not sure
adding one additional symlink and/or replacing php-fpm by php --fpm
in the service definition is any more complicated than that. Doing it
all in a single step would also mean that there is no weird intermediate
state where when providing support we would also need to differentiate
between “FPM” and “FPM as part of CLI”.
Best regard
Tim Düsterhus
I like this idea. Aesthetically, it makes PHP look more like mainstream languages such as Ruby or Python, in my opinion.
Something interesting is that on Linux when configuring a PHP web app with Nginx, every request goes from the server to the php-fpm service (i.e: php8.4-fpm.socket on Debian). I'm actually on openSUSE Leap 16.0, and the socket/service execution step looks like the following:
ExecStart=/usr/sbin/php-fpm --nodaemonize --fpm-config /etc/php8/fpm/php-fpm.conf
So yeah, if the PHP-FPM looks like PHP-CLI, then migrating to a single binary would be ok, as the dynamic libphp.so library is not an option based on your RFC (co.
However, I have a concern about the OS package maintainers from major Linux package repositories (dpkg, rpm and others). I think, in the case that this becomes the default behavior, they would need to be aware that PHP-FPM is now on a symlink of PHP-CLI (else what happens when you download PHP-FPM?). Because they would need to take the required steps to rebundle PHP (configure the symlink of PHP-FPM to php-cli or deprecate it). Something similar to mysql now being a symlink of now MariaDB by default would take in place.
Not forgetting that all of those operating systems would have to configure the PHP-CLI package to include the necessary service manager (systemd) script previously available on PHP-FPM. Because there are also a lot of IT infrastructures that depend on it (think about Docker containers, for instance). Also, how would it clash with users of OSes without systemd (openrc, runit)?.
For the rest, the idea is cool. My concern is around the maintainers of these packages. I think the safest action would be to have it first as a new optional ./configure flag and then progressively pass it to a default behavior. Because this would maybe enable use cases like serverless PHP (the https://bref.sh project) to be able to have that option by default from a specific Docker image of PHP with that config.
And well, I think that having a shared library libphp.so would actually be a way easier solution to fix it. I have a question about that approach: Isn't it possible to do it by default without any PHP modification?
Kind Regards,
David Maye.
El 06/10/2026 12:32 Matthieu Napoli matthieu@mnapoli.fr escribió:
Hi internals,
I'd like to start the discussion on a new RFC: https://wiki.php.net/rfc/single-binary-cli-fpm
It proposes a new
--enable-cli-fpmbuild option that links the FPM SAPI into thephpexecutable. A combinedphpbinary runs FPM when its first argument is--fpm, or when it is invoked under a name starting withphp-fpm(e.g. aphp-fpmsymlink tophp). Everything else is the CLI, unchanged. The standalonephp-fpmexecutable is still built.php script.php # CLI, as today php --fpm --nodaemonize -y /etc/php-fpm.conf # FPM ln -s php php-fpm ./php-fpm --nodaemonize -y /etc/php-fpm.conf # FPM, through a symlinkThe motivation is that the two executables share almost all their code. I did some measurements with Bref on AWS Lambda to illustrate its usefulness for this specific system. Shipping one binary instead of two:
- removes one of the two ~26 MB executables from the runtime (leaving more room under the 250 MB limit for application code)
- cuts the cold start of a minimal FPM application by 70 ms (-25%), because FPM no longer loads a second copy of the engine right after the CLI loaded it
It makes a difference on AWS Lambda, it might also help on other systems where boot speed (autoscaling, serverless, etc.) or disk size is important.
And from a simplicity perspective I like the idea of having a single binary with FPM "built-in".
There's a secondary vote on enabling the option by default, as Marc suggested when I requested RFC karma.
I'd especially welcome feedback from packagers:
- Would you consider shipping
php-fpmas a symlink to a combinedphpbinary, with the FPM package keeping only the configuration and service files?- Should this stay opt-in, or be enabled by default?
The implementation is at https://github.com/php/php-src/pull/23558 (thanks Jakub and Marc for the reviews so far).
Thanks,
Matthieu Napoli
Hi Matthieu,
The motivation is that the two executables share almost all their code. I did some measurements with Bref on AWS Lambda to illustrate its usefulness for this specific system. Shipping one binary instead of two:
- removes one of the two ~26 MB executables from the runtime (leaving more room under the 250 MB limit for application code)
- cuts the cold start of a minimal FPM application by 70 ms (-25%), because FPM no longer loads a second copy of the engine right after the CLI loaded it
It makes a difference on AWS Lambda, it might also help on other systems where boot speed (autoscaling, serverless, etc.) or disk size is important.
And from a simplicity perspective I like the idea of having a single binary with FPM "built-in".
There's a secondary vote on enabling the option by default, as Marc suggested when I requested RFC karma.
I'd especially welcome feedback from packagers:
- Would you consider shipping
php-fpmas a symlink to a combinedphpbinary, with the FPM package keeping only the configuration and service files?- Should this stay opt-in, or be enabled by default?
I like the direction of the proposal and believe it will be a positive change.
In Debian/Ubuntu, shipping SAPIs as separate packages (php-cli,
php-fpm, libapache2-mod-php8.6, etc) is the norm, and to not break
the packages, I would imagine symlinking would be necessary one way or
the other. Alternately, php-fpm could be a shim that calls CLI with
--fpm flag, and it depends on php-cli package.
I'm also concerned about CLI and FPM parameters. For example, CLI has
-F argument is to execute a file, but FPM's -F flag is an alias to
--nodaemonize. Changing what they do based on the binary/symlink
name or another flag (such as --fpm) is not really a good idea.
Thank you,
Ayesh.