Bootstrap abstraction12 min read

Symfony Runtime: a bootstrap abstraction for PHP front controllers

Symfony Runtime is a Composer-based bootstrap abstraction, not an interpreter or server. It lets one front controller work with PHP-FPM, CLI and worker-style backends.

PHP compatibility and project lifecycle

Unknown from the supplied source: it names no supported PHP versions, no PHP 8.4 or 8.5 compatibility, no license for the code, no support policy and no release numbers for symfony/runtime. It is documented as working with PHP-FPM setups and as usable with backends such as PHP-PM, ReactPHP, Swoole and FrankenPHP. The Response and FRANKENPHP_RESET_KERNEL notes are labelled 8.1 in the docs.

Official sources checked 2026-10-22. Browser lessons on this site run PHP 8.5.

What this project is

Symfony Runtime is a PHP component, installed with Composer as symfony/runtime. According to the official documentation, it decouples an application's bootstrapping logic from global state, so the same application can run under runtimes such as PHP-PM, ReactPHP, Swoole and FrankenPHP without changes to the application code.

It is not an interpreter, an application server, or a replacement for PHP. PHP core still executes your code. A server or worker host (PHP-FPM behind Nginx or Apache, a CLI process, or one of the backends above) still receives the work. Symfony Runtime is the thin layer between the entry script and your application object. It is also not a CMS: a product such as Drupal is a separate application, and this component is a reusable building block that frameworks and applications may adopt.

Classification and lifecycle

The classification is a bootstrap abstraction. The source packet does not state a support policy, supported PHP versions or a licence for the code, and the page shows only a documentation license for its text and samples. Those items are unknown here, so the lifecycle is marked unknown. Check the official page and Packagist metadata before depending on it. This course track uses PHP 8.4, with PHP 8.5 planned, but the supplied source does not confirm compatibility with either.

Architecture

When you install the component, a Composer plugin generates vendor/autoload_runtime.php. Your front controller, such as public/index.php, requires that file instead of the normal autoloader, and returns a callable. The generated file then does the following:

  • It instantiates a RuntimeInterface.
  • It includes the front controller, so the script runs again. The docs warn that this must not cause side effects.
  • It passes the returned callable to the runtime, which resolves its arguments.
  • It calls the callable to obtain the application object, for example a Kernel.
  • It asks the runtime for a runner and runs the application.

In the documented internal model, RuntimeInterface::getResolver() returns a resolver, RuntimeInterface::getRunner() returns a RunnerInterface, and run() returns an integer exit status that ends the PHP process.

Execution model

The default runtime is SymfonyRuntime, described as working well with PHP-FPM behind Nginx or Apache. GenericRuntime uses the PHP superglobals. You can choose a class with the APP_RUNTIME environment variable or extra.runtime.class in composer.json. Custom runtimes can target other hosts, and the documentation mentions Swoole and AWS Lambda as examples. A custom runtime is built from a runtime class plus a runner, as in the documented ReactPHP walkthrough.

Closure arguments are resolved by type and name. The array $context argument equals $_SERVER plus $_ENV, array $argv holds command arguments, and array $request holds query, body, files and session. SymfonyRuntime also resolves Request, InputInterface, OutputInterface, Application and Command. The returned application can be an HttpKernelInterface, a Response, a console Command or Application, a RunnerInterface, a callable, or nothing (void).

Classic requests versus persistent workers

In the classic model, PHP-FPM starts each request from a clean state, runs the script and discards it. Leaked state rarely survives. In a persistent worker, one PHP process handles many requests, so the application and its services can live across requests.

The documentation describes this for FrankenPHP worker mode. The runner reuses the same kernel instance for every request in a worker process, which is what makes worker mode fast, but any state captured by the kernel or its services may leak across requests unless the relevant services implement ResetInterface. Leakage can mean user data, caches, open resources or request-specific values appearing in a later request.

The page also documents an opt-in setting for Symfony 8.1: set the FRANKENPHP_RESET_KERNEL environment variable to 1 and the runner clones the application after each request, so the next request starts from a fresh kernel booted from the cached container file. The stated trade-off is a noticeable performance cost compared to the default reuse mode. The page gives no figures, so none are claimed here. The cleanup rules are to audit stateful services, implement ResetInterface where needed, avoid static mutable state, and use the reset option when auditing is unrealistic.

Swoole is named in the docs as a backend. Open Swoole is a separate project that the supplied source does not discuss, so do not assume the two are interchangeable or that this page documents Open Swoole support.

Practical use cases

  • Writing a generic front controller that returns a Kernel, a Response, a console application or a custom runner.
  • Making console entry points and web entry points share one bootstrap style.
  • Preparing an application for worker-style hosts while keeping the entry script unchanged.
  • Packaging bootstrap logic for another host as a runtime class, so maintainers can fix it independently of application code.

Installation approach

Run composer require symfony/runtime. Outside a Symfony application, you must require vendor/autoload.php yourself for autoloading, as the note on the source page says. The docs warn that the Composer --no-plugins option prevents autoload_runtime.php from being created, and that --no-scripts needs Composer 2.1.3 or newer for the file to be created. Modern Composer may also ask you to allow the plugin in config. That setting comes from Composer behavior, not from the supplied page, so confirm it during review. Options such as env, debug, project_dir and dotenv_path can be set via APP_RUNTIME_OPTIONS or extra.runtime. After changing composer.json, regenerate with composer dump-autoload.

Strengths

  • Generic front controllers that avoid direct dependence on globals.
  • A documented extension path through runtime and runner classes.
  • Documented argument and application resolution.
  • Explicit documentation of the FrankenPHP worker reset trade-off.

Limitations

  • It supplies no server, event loop or process manager. You still need a backend.
  • Runtime support for a particular host is separate from this page. Do not assume that every named backend ships a ready-made runtime.
  • The page shows no PHP version matrix, support policy or benchmark.
  • Worker hosts bring state-leak risk that the component cannot fully remove.

Deployment notes

For classic hosting, use PHP-FPM behind a web server and keep FastCGI private, never exposed publicly. For worker backends, follow that backend's own documentation. If you run local development servers, bind them to 127.0.0.1. Runtime examples need Composer and may need network access, so they are not browser exercises.

Where to read more

The single official source for this guide is the Symfony Runtime Component page at https://symfony.com/doc/current/components/runtime.html.

Practical examples

These examples have not been run in a live environment yet. Commands and versions follow the official documentation linked on this page; check them before relying on them, and report a problem if one does not work.

Minimal CLI front controller with a context argument

A Composer project that installs symfony/runtime and defines a front controller returning a closure that receives the array $context argument. It is run from the command line with PHP's CLI, not from a browser. This is a sketch of a documented pattern.

composer.json

{
    "name": "learnphp/runtime-demo",
    "description": "Minimal Symfony Runtime demo",
    "type": "project",
    "require": {
        "symfony/runtime": "*"
    },
    "config": {
        "allow-plugins": {
            "symfony/runtime": true
        }
    }
}

public/index.php

<?php

declare(strict_types=1);

require_once dirname(__DIR__) . '/vendor/autoload_runtime.php';

return function (array $context): void {
    $env = $context['APP_ENV'] ?? 'not set';
    echo 'Hello from Symfony Runtime. env=' . $env . PHP_EOL;
};

Install and run

composer install
APP_ENV=demo php public/index.php

Expected behavior

Composer installs symfony/runtime and generates vendor/autoload_runtime.php. Running the script should print a greeting line that includes the env value, ideally env=demo. The exact value can depend on how the runtime resolves the environment, so review it.

Requirements are a PHP CLI and Composer with network access to download packages. PHP 8.4 compatibility is not confirmed by the source. The allow-plugins entry comes from general Composer behavior, not the supplied page. This is a CLI demo only, with no web server and no worker mode.

Custom RunnerInterface returning an exit code

The same Composer setup with a front controller that returns an anonymous class implementing RunnerInterface, showing how the runtime calls run() and uses the integer result as the exit status. It stays on the CLI, so no network port or FastCGI endpoint is exposed.

composer.json

{
    "name": "learnphp/runtime-runner-demo",
    "description": "Custom runner demo for Symfony Runtime",
    "type": "project",
    "require": {
        "symfony/runtime": "*"
    },
    "config": {
        "allow-plugins": {
            "symfony/runtime": true
        }
    }
}

public/runner.php

<?php

declare(strict_types=1);

use Symfony\Component\Runtime\RunnerInterface;

require_once dirname(__DIR__) . '/vendor/autoload_runtime.php';

return static function (): RunnerInterface {
    return new class implements RunnerInterface {
        public function run(): int
        {
            echo 'Hello from a custom runner' . PHP_EOL;

            return 0;
        }
    };
};

Install and run

composer install
php public/runner.php

Expected behavior

The script should print one line, Hello from a custom runner, and the process should end with exit status 0, which the runtime takes from run().

Requires Composer, network access for installation and a PHP CLI. PHP 8.4 compatibility is not confirmed by the source. It demonstrates only the documented RunnerInterface path. It is not a server, not a worker loop, and shows no state-reset behavior.