hypervel/framework
Hypervel is a Laravel-compatible PHP framework built on Hyperf and Swoole coroutines. It brings familiar Laravel APIs—routing, ORM, queues, events, and validation—to a high-performance, coroutine-driven runtime, so Laravel developers can build fast concurrent apps with almost no learning curve.
Hypervel is Laravel's API surface running on Hyperf/Swoole coroutines. Your app boots once, stays in memory, and each request is a coroutine — so the "Laravel feel" is genuine, but the runtime assumptions are not.
Minimal path:
composer create-project hypervel/hypervel my-app
cd my-app
cp .env.example .env
php artisan key:generate
php artisan migrate
php artisan serve # boots the Swoole server, not php -S
Look here first, in order:
bootstrap/app.php — routing/middleware/exception wiring (Laravel 11-style fluent builder).routes/ — web.php / api.php, plus php artisan route:list to confirm what's actually registered.app/Http/Controllers and app/Http/Middleware — the request entry points.config/ (component defaults often land in config/autoload/) — pool sizes, server settings, coroutine limits live here, and they are read at boot.app/Providers — where you bind interfaces and register listeners; DI is the backbone of the framework.First use case — a JSON endpoint with Eloquent:
// routes/api.php
Route::get('/users/{user}', [UserController::class, 'show']);
// app/Http/Controllers/UserController.php
public function show(User $user)
{
return UserResource::make($user->load('team'));
}
That works exactly like Laravel. The moment it doesn't is when you add caching, concurrency, or per-request state — read the next two sections before you do.
Constructor injection over facades. The container resolves per request and singletons are shared across coroutines, so inject services (__construct(private BillingClient $billing)) and keep them stateless. Facades still work but hide the lifetime question.
Per-request state goes in Context, never in properties. Hypervel\Context\Context::set('tenant', $tenant) is coroutine-local and inherited by child coroutines. This is the single most important habit to build.
Context::set('tenant_id', $request->user()->tenant_id);
// later, anywhere in the request's coroutine tree
$tenantId = Context::get('tenant_id');
Parallelize I/O with coroutines. Sequential HTTP calls are the usual performance trap. Use Hyperf\Coroutine\Parallel or Coroutine::create() + wait() to fan out to downstream services; the whole point of the runtime is that this is cheap.
Wrap transactions in closures. Because connections come from a pool, Db::beginTransaction() held across a coroutine switch is a footgun. Prefer:
Db::transaction(function () use ($order) {
$order->update(['status' => 'paid']);
Payment::create([...]);
});
Push slow work to the queue. Mail, webhooks, exports — dispatch jobs and run php artisan queue:work as a supervised process. Jobs are coroutine-based, so a job that blocks blocks a worker slot.
Cross-cutting concerns via middleware and events. Throttling, tenant resolution, request IDs: middleware writing to Context. Audit trails and cache invalidation: model events / listeners, but keep listeners idempotent since they may run concurrently.
Testing. Standard PHPUnit with the framework's TestCase; use RefreshDatabase as in Laravel. Tests that spawn coroutines need assertions after wait() — don't assert on a Coroutine::create() you never joined.
Deployment. Treat it like a daemon, not PHP-FPM: Supervisor/systemd, php bin/hyperf.php start (or artisan serve in staging), N workers per CPU, graceful reload on deploy. No shared-nothing reset between requests.
static $cache = [], a memoized user on a service, a growing array in a singleton — all of it leaks across users. This is the #1 source of "impossible" bugs in Hypervel/Hyperf apps. Audit any property assignment on a class bound as a singleton.Request object (or an Eloquent model pinned to a request) in a singleton or a static. Grab what you need into Context and let the request die.sleep(), file_get_contents('https://...'), synchronous Guzzle, heavy CPU loops. Use Coroutine::sleep(), the coroutine HTTP client, and offload CPU work to a queue. A blocked worker can stall every coroutine scheduled on it.max_connections / min_connections / wait_timeout in the database and Redis pool config; leaked connections (a manually opened transaction that throws before rollback) will drain the pool under load..env are read at boot. Editing a config file does nothing until you restart, unless you're running with the watcher. Don't expect Laravel's per-request config freshness.dd() / dump() / var_dump() land in the server console, not the HTTP response. Reach for logger() or return the data when you're actually debugging a browser request.runtime/logs/, not storage/logs/. Uncaught exceptions inside a coroutine may be logged rather than rendered — check there first when a response is empty or the connection resets.register_shutdown_function, or raw cURL will misbehave. Prefer Hyperf-native or Hypervel-maintained equivalents, and read the source of anything stateful before installing.Context for request scope, #[Timeout] / coroutine timeout settings for downstream calls, the container's bind/singleton distinction, and custom ConfigProvider classes if you're writing a package that publishes config.composer.json, read changelogs before upgrading, and keep a smoke test around the request lifecycle — breaking changes land in minor releases.How can I help you explore Laravel packages today?