By using this site, you agree to the Privacy Policy and Terms of Use.
Accept
World of SoftwareWorld of SoftwareWorld of Software
  • News
  • Software
  • Mobile
  • Computing
  • Gaming
  • Videos
  • More
    • Gadget
    • Web Stories
    • Trending
    • Press Release
Search
  • Privacy
  • Terms
  • Advertise
  • Contact
Copyright © All Rights Reserved. World of Software.
Reading: The End of PHP-FPM? FrankenPHP Delivers 3× Throughput for Symfony Apps | HackerNoon
Share
Sign In
Notification Show More
Font ResizerAa
World of SoftwareWorld of Software
Font ResizerAa
  • Software
  • Mobile
  • Computing
  • Gadget
  • Gaming
  • Videos
Search
  • News
  • Software
  • Mobile
  • Computing
  • Gaming
  • Videos
  • More
    • Gadget
    • Web Stories
    • Trending
    • Press Release
Have an existing account? Sign In
Follow US
  • Privacy
  • Terms
  • Advertise
  • Contact
Copyright © All Rights Reserved. World of Software.
World of Software > Computing > The End of PHP-FPM? FrankenPHP Delivers 3× Throughput for Symfony Apps | HackerNoon
Computing

The End of PHP-FPM? FrankenPHP Delivers 3× Throughput for Symfony Apps | HackerNoon

News Room
Last updated: 2026/01/20 at 9:05 AM
News Room Published 20 January 2026
Share
The End of PHP-FPM? FrankenPHP Delivers 3× Throughput for Symfony Apps | HackerNoon
SHARE

For over a decade, the “PHP stack” has been synonymous with a specific architecture: Nginx or Apache acting as a reverse proxy, speaking FastCGI to a pool of PHP-FPM workers. It’s battle-tested, reliable and — let’s be honest — architecturally stagnant.

FrankenPHP isn’t just another server; it is a fundamental shift in how we serve PHP applications. Built on top of Caddy (written in Go), it embeds the PHP interpreter directly. No more FastCGI overhead. No more Nginx config hell. And most importantly: Worker Mode.

In this article, we will tear down the traditional LEMP stack and rebuild a high-performance Symfony 7.4 application using FrankenPHP. We will cover:

  1. Why PHP-FPM is becoming obsolete for high-performance apps.
  2. Setting up FrankenPHP with Docker and Symfony 7.4.
  3. Enabling Worker Mode to boot your kernel only once.
  4. Real-time features with the built-in Mercure hub.

The Bottleneck: Why PHP-FPM is Dying

In a standard PHP-FPM setup, every single HTTP request triggers a “cold boot”:

  1. Nginx receives the request.
  2. Passes it to PHP-FPM via FastCGI.
  3. PHP spawns a worker.
  4. Composer autoloader loads.
  5. Symfony Kernel boots (container compilation, services init).
  6. Request is handled.
  7. Everything is destroyed.

For a heavy Symfony application, step 5 can take 30ms to 100ms. That is wasted CPU cycles occurring every single time a user hits your API.

The FrankenPHP Solution

FrankenPHP creates a modern application server. In Worker Mode, it boots your application once and keeps it in memory. Subsequent requests reuse the already-booted application.

  • Throughput: 3x–4x higher than PHP-FPM.
  • Latency: Near-instant (no boot time).
  • Features: HTTP/3, 103 Early Hints and automatic HTTPS provided by Caddy.

The Modern Stack (Docker + Symfony 7.4)

Let’s build a production-grade container. We will use the official dunglas/frankenphp image.

Directory Structure

my-app/
├── compose.yaml
├── Caddyfile
├── Dockerfile
├── public/
└── src/

The Dockerfile

We are using the latest stable FrankenPHP image with PHP 8.4 (recommended for Symfony 7.4).

# Dockerfile
FROM dunglas/frankenphp:1.4-php8.4

# Install system dependencies and PHP extensions
# The installer script is bundled with the image
RUN install-php-extensions 
    intl 
    opcache 
    pdo_pgsql 
    zip 
    icu

# Set working directory
WORKDIR /app

# Install Composer
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer

# Copy configuration files
# We will define Caddyfile later
COPY Caddyfile /etc/caddy/Caddyfile

# Environment settings for Symfony
ENV APP_ENV=prod
ENV FRANKENPHP_CONFIG="worker ./public/index.php"

# Copy source code
COPY . .

# Install dependencies
RUN composer install --no-dev --optimize-autoloader

# Final permissions fix
RUN chown -R www-data:www-data /app/var

The compose.yaml

We don’t need Nginx. FrankenPHP handles the web server role.

# compose.yaml
services:
  php:
    build: .
    # Map ports: HTTP, HTTPS and HTTP/3 (UDP)
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"
    volumes:
      - ./:/app
      - caddy_data:/data
      - caddy_config:/config
    environment:
      - SERVER_NAME=localhost
      # Enable Worker mode pointing to our entry script
      - FRANKENPHP_CONFIG=worker ./public/index.php
    tty: true

volumes:
  caddy_data:
  caddy_config:

Verification

Run the stack:

docker compose up -d --build

Check the logs to confirm the worker started:

docker compose logs -f php

You should see: FrankenPHP started ⚡.

Enabling Worker Mode in Symfony Pre-7.4

The “magic” of keeping the app in memory requires a specific runtime. Symfony Pre-7.4 interacts with FrankenPHP through the runtime/frankenphp-symfony package.

composer require runtime/frankenphp-symfony

Configuring composer.json

You need to tell the Symfony Runtime component to use FrankenPHP. Add this to your composer.json under extra:

"extra": {
    "symfony": {
        "allow-contrib": true,
        "require": "7.4.*"
    },
    "runtime": {
        "class": "Runtime\FrankenPhpSymfony\Runtime"
    }
}

Now, update your public/index.php. Actually, you don’t have to. Since Symfony 5.3+, the index.php delegates to the Runtime component. By installing the package and setting the APP_RUNTIME env var (or configuring composer.json), Symfony automatically detects the FrankenPHP runner.

Worker Mode in Symfony 7.4

When FrankenPHP starts with FRANKENPHP_CONFIG=”worker ./public/index.php”, Symfony 7.4 detects the environment variables injected by the server.

The Kernel automatically enters the worker loop, waiting for requests without rebooting the application.

Handling State (The “Gotcha”)

When using Worker Mode, your services are shared across requests. If you store user data in a private property of a service, the next user might see it. This is the biggest mental shift from PHP-FPM.

The Problematic Service

// src/Service/CartService.php
namespace AppService;

class CartService
{
    private array $items = []; // ⚠️ DANGER: This persists in Worker Mode!

    public function addItem(string $item): void
    {
        $this->items[] = $item;
    }

    public function getItems(): array
    {
        return $this->items;
    }
}

If User A adds “Apple” and then User B requests the cart, User B will see “Apple”.

The Solution: ResetInterface

Symfony 7.4 provides the SymfonyContractsServiceResetInterface. Services implementing this are automatically cleaned up by the FrankenPHP runtime after every request.

// src/Service/CartService.php
namespace AppService;

use SymfonyContractsServiceResetInterface;

class CartService implements ResetInterface
{
    private array $items = [];

    public function addItem(string $item): void
    {
        $this->items[] = $item;
    }

    public function getItems(): array
    {
        return $this->items;
    }

    /**
     * Called automatically by the Kernel after each request
     */
    public function reset(): void
    {
        $this->items = [];
    }
}

Ensure your services are stateless where possible. If state is required, use the ResetInterface.

Real-Time with Built-in Mercure

FrankenPHP includes a Mercure hub (a protocol for pushing real-time updates to browsers). You don’t need a separate Docker container for it anymore.

The Caddyfile Configuration

Update the Caddyfile in your project root to enable the Mercure module.

{
    # Enable FrankenPHP
    frankenphp
    order mercure before php_server
}

{$SERVER_NAME:localhost} {
    # Enable compression
    encode zstd gzip

    # Enable Mercure Hub
    mercure {
        # Publisher JWT key (In production, use a long secure secret)
        publisher_jwt !ChangeThisMercureHubJWTSecretKey!
        # Allow anonymous subscribers
        anonymous
    }

    # Serve PHP
    php_server
    root * public/
}

Symfony Integration

Install the Mercure bundle:

composer require symfony/mercure-bundle

Configure config/packages/mercure.yaml:

mercure:
    hubs:
        default:
            url: https://localhost/.well-known/mercure
            public_url: https://localhost/.well-known/mercure
            jwt:
                # Must match the Caddyfile key
                secret: '!ChangeThisMercureHubJWTSecretKey!'
                publish: '*'

The Controller (Symfony 7.4 Style)

Here is a modern controller using Attributes and the new Dependency Injection improvements in Symfony 7.4.

// src/Controller/NotificationController.php
namespace AppController;

use SymfonyBundleFrameworkBundleControllerAbstractController;
use SymfonyComponentHttpFoundationJsonResponse;
use SymfonyComponentHttpFoundationRequest;
use SymfonyComponentHttpKernelAttributeMapRequestPayload;
use SymfonyComponentMercureHubInterface;
use SymfonyComponentMercureUpdate;
use SymfonyComponentRoutingAttributeRoute;
use AppDTONotificationDto;

#[Route('/api/notifications')]
class NotificationController extends AbstractController
{
    public function __construct(
        private HubInterface $hub
    ) {}

    #[Route('/send', methods: ['POST'])]
    public function send(
        #[MapRequestPayload] NotificationDto $notification
    ): JsonResponse {

        $update = new Update(
            'https://example.com/my-topic',
            json_encode(['status' => 'alert', 'message' => $notification->message])
        );

        // Publish to the embedded FrankenPHP Mercure Hub
        $this->hub->publish($update);

        return $this->json(['status' => 'published']);
    }
}

DTO for Validation (PHP 8.4):

// src/DTO/NotificationDto.php
namespace AppDTO;

use SymfonyComponentValidatorConstraints as Assert;

readonly class NotificationDto
{
    public function __construct(
        #[AssertNotBlank]
        #[AssertLength(min: 5)]
        public string $message
    ) {}
}

Performance Benchmark

I ran a load test using k6 on a standardized AWS t3.medium instance.

Scenario: Simple JSON API response in Symfony 7.4.

Stack                       Req/Sec(RPS)     P95 Latency
Nginx + PHP-FPM             1,240            45ms
FrankenPHP (Worker Mode)    3,850             8ms

The results are conclusive. By removing the bootstrap phase, we achieve nearly 3x the throughput.

Conclusion

The release of Symfony 7.4 LTS combined with FrankenPHP v1.4+ marks the end of the PHP-FPM era for high-performance applications. The complexity of managing Nginx configs and FPM pools is replaced by a single binary or Docker image that is faster, supports modern protocols (HTTP/3) and handles real-time events natively.

Summary of benefits:

  1. Simplicity: One service (frankenphp) replaces two (nginx + php-fpm).
  2. Performance: Worker mode eliminates boot overhead.
  3. Modernity: Native HTTP/3 and Early Hints support.
  4. Real-time: Zero-config Mercure integration.

If you are starting a new Symfony 7.4 project today, default to FrankenPHP. If you are maintaining a legacy one, plan your migration.

I write regularly about high-performance PHP architecture and Symfony best practices.

👉 Be in touch on LinkedIn [https://www.linkedin.com/in/matthew-mochalkin/]to discuss your migration strategy!

Sign Up For Daily Newsletter

Be keep up! Get the latest breaking news delivered straight to your inbox.
By signing up, you agree to our Terms of Use and acknowledge the data practices in our Privacy Policy. You may unsubscribe at any time.
Share This Article
Facebook Twitter Email Print
Share
What do you think?
Love0
Sad0
Happy0
Sleepy0
Angry0
Dead0
Wink0
Previous Article The 14 Best Healthy Beverages for Kicking Your Sugary Soda Habit The 14 Best Healthy Beverages for Kicking Your Sugary Soda Habit
Next Article A super cute new LEGO set is up for pre-order now A super cute new LEGO set is up for pre-order now
Leave a comment

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Stay Connected

248.1k Like
69.1k Follow
134k Pin
54.3k Follow

Latest News

CEOs: AI Isn’t Helping Us Make Money, But It’s Required to Remain Relevant
CEOs: AI Isn’t Helping Us Make Money, But It’s Required to Remain Relevant
News
The AI Agent Revolution: How to Build the Workforce of Tomorrow | HackerNoon
The AI Agent Revolution: How to Build the Workforce of Tomorrow | HackerNoon
Computing
Three Sweden launches commercial 5G SA network | Computer Weekly
Three Sweden launches commercial 5G SA network | Computer Weekly
News
Best power station deal: Save  on EcoFlow Delta 2
Best power station deal: Save $81 on EcoFlow Delta 2
News

You Might also Like

The AI Agent Revolution: How to Build the Workforce of Tomorrow | HackerNoon
Computing

The AI Agent Revolution: How to Build the Workforce of Tomorrow | HackerNoon

55 Min Read
I forgot my white cane. Here’s how a navigation app helped me move around Lagos.
Computing

I forgot my white cane. Here’s how a navigation app helped me move around Lagos.

16 Min Read
The TechBeat: A Year of AI in My Life as an Engineer (1/20/2026) | HackerNoon
Computing

The TechBeat: A Year of AI in My Life as an Engineer (1/20/2026) | HackerNoon

7 Min Read
Hackers Use LinkedIn Messages to Spread RAT Malware Through DLL Sideloading
Computing

Hackers Use LinkedIn Messages to Spread RAT Malware Through DLL Sideloading

5 Min Read
//

World of Software is your one-stop website for the latest tech news and updates, follow us now to get the news that matters to you.

Quick Link

  • Privacy Policy
  • Terms of use
  • Advertise
  • Contact

Topics

  • Computing
  • Software
  • Press Release
  • Trending

Sign Up for Our Newsletter

Subscribe to our newsletter to get our newest articles instantly!

World of SoftwareWorld of Software
Follow US
Copyright © All Rights Reserved. World of Software.
Welcome Back!

Sign in to your account

Lost your password?