____ _ ____ _
| _ \(_)___ _ __ | _ \| | _____ __
| |_) | / __|| '_ \ | |_) | |/ _ \ \ /\ / /
| __/| \__ \| |_) | | __/| | (_) \ V V /
|_| |_|___/| .__/ |_| |_|\___/ \_/\_/
|_|
Laravel Octane supports Swoole, FrankenPHP, and RoadRunner — but none of them work on Windows. Phyra fills that gap by bringing the same persistent-runtime performance to Workerman, a pure-PHP application server that runs on Linux, macOS, and Windows — no C extensions, no compilation, no WSL required.
Quick Start · Why Phyra? · Configuration · Docs · FAQ
composer require phyra/workerman-bridge
php artisan vendor:publish --tag=phyra-config
php artisan phyra:serveThat's it. Your Laravel app now runs on a persistent Workerman process. No code changes required for most applications.
____ _ ____ _
| _ \(_)___ _ __ | _ \| | _____ __
| |_) | / __|| '_ \ | |_) | |/ _ \ \ /\ / /
| __/| \__ \| |_) | | __/| | (_) \ V V /
|_| |_|___/| .__/ |_| |_|\___/ \_/\_/
|_|
Laravel on Workerman — fast, memory-safe, state-leak-aware.
Host: 0.0.0.0
Port: 8080
Workers: auto-detect
Max req: 10000 per worker📦 Not on Packagist yet? Install from GitHub instead — see Installation.
Laravel is the most productive PHP framework. Workerman is a fast, persistent PHP application server written in pure PHP (no extra extensions required on Windows). They're a great combo — but Laravel assumes a fresh process per request, while Workerman keeps your app alive forever.
Phyra bridges that gap with a proper state management engine so your Laravel app runs safely inside a long-lived worker.
| Feature | PHP-FPM | Octane (Swoole) | Phyra (Workerman) |
|---|---|---|---|
| Persistent process (no boot per request) | ❌ | ✅ | ✅ |
| Pure PHP (no C extensions) | ✅ | ❌ | ✅ |
| Works on Windows | ✅ | ❌ | ✅ |
| Multi-process workers | ✅ | ✅ | ✅ (Linux) |
| Stop / status / reload commands | n/a | ✅ | ✅ (cross-platform) |
| Sandbox state isolation | ❌ | ✅ | ✅ |
| Drop-in for existing Laravel app | ✅ |
Phyra is independent and not affiliated with Laravel Octane, though it borrows the well-tested sandbox pattern. The same Octane compatibility rules apply — see State leaks & limitations.
- Octane-style sandbox — clones the app per request, rebinds the Kernel & Router to the sandbox, then restores them. Config / locale / container / facade / view / session / auth state is isolated between requests.
- Cross-platform control plane —
phyra:status,phyra:stopandphyra:reloadwork on Windows too (via a pid + heartbeat + stop-sentinel mechanism), not just on Linux. - Persistent DB connections — connections stay alive across requests with auto-reconnect on dead sockets and automatic rollback of leaked transactions.
- Worker recycling — workers are recycled after N requests or when they exceed a memory limit, preventing slow memory growth.
- Hot reload in development — file monitor reloads on code changes (smooth on Linux, full-stop on Windows).
- Laravel-native — registers as a ServiceProvider + Facade, publishes a config file, ships Artisan commands. Feels like part of Laravel.
┌─────────────────────────────────────────────────────────┐
│ Your Laravel 13.x app (unchanged) │
├─────────────────────────────────────────────────────────┤
│ Phyra State Engine │
│ ├── Per request: clone base app → sandbox │
│ ├── Rebind HTTP Kernel + Router → sandbox │
│ ├── Handle request through sandbox │
│ ├── Restore Kernel + Router → base app │
│ ├── Flush sandbox + reset base state │
│ │ · config · locale · facades · view cache │
│ │ · container scoped · session · auth │
│ └── Worker recycle (max requests + memory limit) │
├─────────────────────────────────────────────────────────┤
│ Database / Redis │
│ ├── Persistent connections across requests │
│ ├── Auto-reconnect on dead connections │
│ └── Auto-rollback leaked transactions │
├─────────────────────────────────────────────────────────┤
│ Workerman 5.2 (persistent HTTP server, pure PHP) │
└─────────────────────────────────────────────────────────┘
A deep dive is in docs/architecture.md.
Run the included benchmark against your own app and compare with PHP-FPM:
# Start Phyra
php artisan phyra:serve --port=8080
# Benchmark it (requires `wrk`)
wrk -t4 -c64 -d30s http://localhost:8080
# Compare with artisan serve / PHP-FPM
php artisan serve --port=8000
wrk -t4 -c64 -d30s http://localhost:8000Or use the bundled script:
php benchmark/run.php http://localhost:8080 10 64Real numbers depend entirely on your app, hardware, and workload — so measure your own. As a baseline reference, a trivial "hello world" route on a single Windows worker handled ~120 req/s with zero memory growth across 500 requests in our smoke test. On Linux with multiple workers and a real workload, throughput scales roughly linearly with worker count.
See docs/benchmark.md for a honest methodology.
Publish the config:
php artisan vendor:publish --tag=phyra-config// config/phyra.php
return [
'server' => [
'host' => env('PHYRA_HOST', '0.0.0.0'),
'port' => env('PHYRA_PORT', 8080),
'workers' => env('PHYRA_WORKERS', null), // auto on Linux, 1 on Windows
'name' => env('PHYRA_SERVER_NAME', 'Phyra'),
'control_dir' => env('PHYRA_CONTROL_DIR', null), // null = storage/framework/phyra
],
'worker' => [
'max_requests' => env('PHYRA_MAX_REQUESTS', 10000), // recycle after N
'memory_limit' => env('PHYRA_MEMORY_LIMIT', '128M'), // recycle if exceeded
'reload' => env('PHYRA_RELOAD', false),
],
'file_monitor' => [
'enabled' => env('PHYRA_FILE_MONITOR', null), // null = auto (on when APP_DEBUG)
'extensions' => ['php', 'env', 'html', 'htm'],
'poll_interval' => 1,
],
'state' => [
'flush' => ['config' => true, 'locale' => true, 'facade' => true,
'view' => true, 'container' => true, 'request' => true],
],
'database' => [
'auto_reconnect' => true,
'rollback_leaked_transactions' => true,
],
];Full reference: docs/configuration.md.
php artisan phyra:serve # Start the server
php artisan phyra:status # Is it running? (cross-platform)
php artisan phyra:stop # Stop the server (cross-platform)
php artisan phyra:reload # Smooth restart (Linux) / full stop (Windows)You can also use the Phyra Facade in your app:
use Phyra\Workerman\Facades\Phyra;
if (Phyra::isRunning()) {
// running inside a Phyra worker
}Phyra runs on both Linux and Windows. Workerman itself has different capabilities per platform — be aware of the differences:
| Capability | Linux / macOS | Windows |
|---|---|---|
| Multiple worker processes | ✅ yes | ❌ single process only |
pcntl / posix (signals) |
✅ required | ❌ not available |
phyra:stop |
✅ SIGTERM | ✅ via stop-sentinel file |
phyra:reload (smooth) |
✅ SIGUSR1 | |
phyra:status |
✅ pid + posix check | ✅ heartbeat-based check |
| Daemon / background | ✅ yes | ❌ runs in the terminal |
| File-monitor hot reload | ✅ smooth reload |
Windows is great for development. For production, run on Linux to get multi-process workers, daemonization and smooth reload. More in docs/windows.md.
composer testThe suite covers real state isolation (config/locale don't leak across requests), the cross-platform control plane, DB connection pool safety, command registration, and worker recycling.
Is Phyra a drop-in replacement for PHP-FPM?
For most apps, yes. But because the worker stays alive between requests, you
must follow the same rules as Laravel Octane — avoid static variables in
route closures, don't accumulate listeners per request, etc. See
State leaks & limitations.
How is this different from Laravel Octane?
Octane supports FrankenPHP, Swoole and RoadRunner — not Workerman. Phyra is an independent bridge that targets Workerman specifically. It uses the same sandbox pattern as Octane, so the same compatibility rules apply.
Does it work on Windows?
Yes — including phyra:status and phyra:stop, which normally require POSIX
signals. Phyra ships a cross-platform control plane (pid + heartbeat +
stop-sentinel). Windows is limited to a single worker process and no smooth
reload, so use Linux for production.
Will my static counter leak between requests?
Yes — that's a fundamental PHP limitation, not something any bridge can fix. Move shared state to the cache or database. See State leaks & limitations.
Where are the control files written?
To storage/framework/phyra/ by default (phyra.pid, phyra.heartbeat,
phyra.stop). Override with PHYRA_CONTROL_DIR.
- Packagist publication (
composer require phyra/workerman-bridge) - WebSocket / async support via Workerman protocols
- Optional Octane-compatible runtime interface
- CI on Linux + Windows
- More integration tests with real Laravel features (queues, mail, broadcasts)
Contributions are welcome! Please read CONTRIBUTING.md and the Code of Conduct before opening a PR.
MIT — see LICENSE.
If Phyra saves you boot time per request, give it a ⭐ to help others find it.