A PHP framework for serious software

Fast, explicit, and small enough to understand. Crab gives long-lived PHP applications a clear foundation for APIs, services, and the work around them.

PHP 8.4 · MIT · open source

composer create-project crabphp/crab my-app
cd my-app
php cua dev

Read the documentation

One way to do each thing

Explicit
Typed actions, named services, ordinary PHP. The important parts stay visible instead of hiding behind conventions.
Long-lived
The application loads once and serves requests as a real server. No PHP-FPM, no bootstrapping on every request.
Complete
Routing, validation, databases, queues, scheduling, authentication, HTTP, streaming, and WebSockets on one small foundation.

Included

A route is just a route

// routes/web.php
use Crab\Route;

Route::get('/hello/{name}', static function (string $name): array {
    return ['hello' => $name];
});

Written for agents too

Explicit types, no hidden state, one way to do each thing. The same things that make code easy for a person to read make it easy for a coding agent to get right.

$ php cua describe routes
routes
  POST /orders -> App\Actions\PlaceOrder via Crab\Auth\TokenAuth
    body { lines: Array<{ productId: int; quantity?: int | null (minimum=1, maximum=20, default=1) }> (minItems=1, maxItems=20) }
    user: App\User
  GET /products/{id} -> App\Actions\ShowProduct
    {id}: int
describe
The whole application in one read: routes and what each takes, middleware, commands, schedule, listeners, databases, settings. One thing per line, in few tokens. --json gives JSON Schema.
AGENTS.md
Every new app ships with one: where things go, the rules a long-lived server needs, and how to check the work.
problem:
describe app lists settings that do not fit and services that cannot be made, before start refuses them.
Markdown
The guide is plain Markdown, in vendor/crabphp/framework/docs/ and at /llms.txt.

Describing the application

One command runs all of it

HTTP, queue workers, and the scheduler start together. No Supervisor config, no systemd unit per worker, no crontab line. List the queue and the scheduler in app.php, then start.

$ php cua start --daemon
Starting Shop server on http://127.0.0.1:8080

  Server    Workers  Runs
  http      2        http://127.0.0.1:8080
  queue     3        queue:work: mail x1, default x2
  schedule  1        schedule:work
--daemon
Runs in the background and returns once it is up. A worker that dies is started again.
reload
HTTP, the queue, and the scheduler get the new code together, without refusing a connection.
status
Every worker, what it has handled, and its memory, in one table.

Deployment guide

Benchmarks

Requests per second, median, 64 persistent connections.

FrameworkHelloDatabaseValidation
Crab200,40118,367101,389
webman Workerman146,8988,31411,873
Hyperf Swoole97,04820,10213,225
Symfony FrankenPHP12,7187,44210,116
Spiral RoadRunner5,5193,6544,912
Laravel Octane4,1062,4632,870
Tempest FrankenPHPneeds PHP 8.5

Measured on one Apple M1 Pro with small, matched workloads. Not a universal ranking or a capacity estimate. Methodology and raw results