Laravel Octane en Laravel 13: acelera tu app con FrankenPHP, Swoole o RoadRunner
Con PHP-FPM cada request arranca y destruye el framework; con Laravel Octane la app se bootea una vez y queda viva en memoria, con ganancias de 3 a 4 veces en throughput y TTFB. Esta guía cubre instalación, servidores, memoria y producción.
Por qué PHP-FPM deja rendimiento sobre la mesa
El ciclo de vida de un request en PHP-FPM
En un despliegue clásico, cada petición ejecuta index.php desde cero: se carga el framework, se bootean todos los service providers, se resuelve el contenedor de dependencias, se genera la respuesta y al terminar el proceso muere o vuelve al pool de FPM con la memoria liberada. Ese arranque completo se repite con cada request, y es justamente el costo que pagas en el TTFB aunque tu lógica de negocio tarde milisegundos.
Qué cambia con Octane: workers que viven en memoria
Octane invierte la lógica: la aplicación se inicializa una vez y el worker queda escuchando peticiones durante toda su vida. Los siguientes requests reutilizan el framework ya booteado, sin repetir la carga de providers ni la resolución del contenedor. El resultado es un tiempo de respuesta mucho más bajo y un throughput mayor, porque el trabajo pesado de arranque se paga una sola vez por worker.
Elegir servidor: FrankenPHP vs Swoole vs RoadRunner
FrankenPHP: el recomendado por defecto (Go + Caddy)
Desde Laravel 11, FrankenPHP es el servidor que Octane sugiere por defecto. Es un binario que combina Go y Caddy con un modo worker de PHP, así que sirve HTTP, gestiona certificados TLS y ejecuta tu aplicación en un solo proceso. Para la mayoría de los proyectos es la opción más simple de operar, porque no requiere instalar extensiones de PHP adicionales.
Swoole y Open Swoole: el techo más alto y el precipicio más empinado
Swoole y Open Swoole son extensiones de PHP que añaden un scheduler de corutinas. Ofrecen el mejor rendimiento de los tres y acceso a APIs exclusivas de Octane, pero también exigen más cuidado: hay que compilar o instalar la extensión, entender cómo conviven las corutinas con el resto del código y operar un runtime más exigente. Si no necesitas sus funciones especiales, pagas complejidad sin usarla.
RoadRunner: el binario de Go sin corutinas
RoadRunner es un servidor de aplicación escrito en Go que se comunica con workers PHP. Es una opción sólida si ya trabajas con Go en tu equipo o prefieres un binario independiente del runtime de PHP. No ofrece las APIs de corutinas de Swoole, pero sí workers persistentes con un buen balance entre rendimiento y simplicidad de operación.
Instalación en Laravel 13
composer require laravel/octane y octane:install
La instalación empieza con el paquete oficial y el comando interactivo que configura el servidor elegido:
composer require laravel/octane
php artisan octane:install --server=frankenphpPuedes usar --server=swoole, --server=open-swoole o --server=roadrunner según lo que decidas en la sección anterior. El comando publica la configuración necesaria y, en el caso de FrankenPHP, deja listo el binario para tu plataforma.
Arrancar el servidor: octane:start y sus opciones
Con el servidor instalado, lo levantas con octane:start. El siguiente ejemplo escucha en todas las interfaces en el puerto 8080:
php artisan octane:start --server=frankenphp --host=0.0.0.0 --port=8080Si usas FrankenPHP y necesitas personalizar el comportamiento de Caddy (middleware, routing o directivas propias), puedes pasar tu propio Caddyfile con --caddyfile=/ruta/Caddyfile.
Workers y max-requests: la red de seguridad contra fugas
Octane levanta varios workers para aprovechar los núcleos de la máquina. Puedes controlarlos al arrancar:
php artisan octane:start --workers=4 --task-workers=6 --max-requests=500--max-requests define cuántas peticiones atiende un worker antes de reiniciarse de forma elegante; el valor por defecto es 500. Es tu red de seguridad principal contra fugas de memoria: aunque algo en tu código retenga memoria entre requests, el worker se recicla al llegar al límite y la fuga no crece para siempre.
La trampa de la memoria en workers persistentes
Por qué las propiedades estáticas se quedan vivas entre requests
En PHP-FPM ese problema no existe porque el proceso muere al terminar cada petición. Con Octane, el worker permanece vivo y todo lo que vive más allá del request se acumula. Una propiedad estática, un singleton mal gestionado o una caché guardada en una variable de clase persisten durante toda la vida del worker. Es el tradeoff que explica buena parte de la ganancia de rendimiento: el estado que no se limpia se queda, para bien y para mal.
Qué resetea Laravel y qué debe resetear el desarrollador
Laravel y Octane resetean el estado del framework entre requests: el contenedor, los facades, las sesiones y los servicios propios de la aplicación se restauran automáticamente. Lo que no se toca es el estado que tú creas: propiedades estáticas de tus clases, cierres capturados en variables de ámbito superior o cachés en memoria. Si tu código guarda algo en una propiedad estática esperando que desaparezca, en Octane no desaparecerá. La regla práctica es revisar cada uso de static y cada singleton propio, y apoyarse en --max-requests como contención de emergencia. Hay casos reales documentados donde una caché en propiedad estática que nunca se purgaba terminaba tirando el servidor en producción; la solución pasó por resetear ese estado explícitamente.
APIs exclusivas de Swoole: Octane::concurrently, ticks y cache
Si eliges Swoole u Open Swoole, Octane expone funciones que no existen en los otros servidores. La más útil es Octane::concurrently(), que ejecuta varios cierres en paralelo dentro de un mismo worker y devuelve los resultados cuando todos terminan, ideal para hacer varias consultas o llamadas externas a la vez. También tienes ticks e intervalos para tareas repetitivas y una Octane cache con tablas en memoria compartida entre workers. FrankenPHP y RoadRunner no pueden ofrecer estas APIs porque carecen del scheduler de corutinas de Swoole; si las necesitas, esa es la razón para elegir Swoole.
Producción: Nginx, systemd y despliegues sin caídas
Octane detrás de Nginx como reverse proxy
En producción, Octane no debe quedar expuesto directamente. Nginx actúa como reverse proxy y se encarga de los assets estáticos, mientras Octane escucha en local. Un bloque mínimo de servidor sería:
server {
listen 80;
server_name tu-app.com;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}
location ~* \.(css|js|png|jpg|svg|woff2)$ {
root /var/www/tu-app/public;
expires 30d;
}
}Gestionar el proceso con systemd o Supervisor
Octane debe correr como un servicio supervisado para arrancar con el sistema y reiniciarse si cae. Un servicio systemd típico ejecuta el comando octane:start con las opciones de workers y max-requests, define el usuario del proyecto y reinicia el proceso en caso de fallo. Supervisor es la alternativa habitual si ya lo usas para otras tareas; la idea es la misma: un proceso con reinicio automático y logs centralizados.
Estrategia de deploy con reinicio gradual de workers
El punto delicado del despliegue es que los workers siguen sirviendo la versión anterior hasta que se reinician. En lugar de matar todos los procesos de golpe, se reinician de forma gradual para no cortar peticiones en curso: Octane recibe la señal, termina los workers uno a uno y los reemplaza por la nueva versión. En la práctica el deploy se compone de dos pasos: actualizar el código y lanzar php artisan octane:reload (o reiniciar el servicio de forma controlada) para que los workers carguen los cambios sin ventana de caída.
Cuándo NO usar Octane
Octane no es gratis ni universal. Si tu aplicación depende mucho de propiedades estáticas o de singletons con estado mutable, la migración puede costar más de lo que ahorra. Tampoco conviene si ejecutas workers de cola pesados dentro del mismo proceso, porque una tarea que bloquee el event loop afecta a todas las peticiones del worker. Y en hosting compartido o plataformas que no permiten procesos persistentes, Octane simplemente no tiene donde vivir. Evalúa primero: si tu cuello de botella es la base de datos o el código de negocio, el servidor de aplicación no lo resolverá.
Conclusión
Laravel Octane es la vía directa para dejar de pagar el arranque del framework en cada request: elige FrankenPHP para empezar simple, Swoole si necesitas corutinas, y controla siempre los workers con max-requests. Antes de lanzarlo a producción, revisa tus estáticas, ponlo detrás de Nginx y planea el reinicio gradual. Si te interesa el rendimiento de tu aplicación, también puedes revisar cómo bajar el TTFB con caché de página o qué trajo Laravel 13 en su guía de novedades. Prueba Octane en un entorno con carga real y mide: los números decidirán por ti.