01
Types are the contract.
One input class is the validation, the OpenAPI documentation and the client SDK. Send the wrong shape and you get every error at once, with its path.
- unknown
- Fields the class does not declare are refused, not ignored.
- required
- A non-nullable property with no default must be sent.
- count
- Constraints are attributes on the same property.
02
What is in the box.
-
Compiled & concurrent
Routes, DI, validation and serialization compile to plain PHP.
keel runserves many requests per process on an event loop, with non-blocking PostgreSQL and Redis. -
Secure by default
Every endpoint requires authentication unless marked
#[Anonymous]. Tokens are bound to their client, DPoP and OpenID Connect built in. Production refuses unsafe settings. -
Multi-tenancy in SQL
Tenant isolation is enforced in the SQL itself. Not by convention, not by a filter you have to remember.
-
A compiled ORM, checked by PHPStan
No lazy loading, no hidden queries. SQLite, PostgreSQL, MySQL, SQL Server and Oracle.
-
Jobs & transactional outbox
Jobs written in the same transaction as your data, relayed to Redis Streams, SQS or RabbitMQ. A scheduler and signed webhooks.
-
Real time
WebSockets and server-sent events on the same endpoints and auth as the rest of the API, with a hub across nodes.
-
Agent-friendly
OpenAPI and a TypeScript SDK from your types. TOON, a token-efficient format for AI agents.
keel inspect. -
Observable
Traces, metrics and logs, from the first request.
-
Native FIX protocol
A FIX trading-protocol engine, native to the framework.
-
Encrypted end to end
AES-256-GCM columns with key rotation, and request and response bodies encrypted past every proxy.
-
Money and ledgers
Exact money, IBAN and card checks, and a double-entry ledger whose history cannot change unnoticed.
-
Microservices and NoSQL
Calls with identity, trace and deadlines; CloudEvents through the outbox; MongoDB, DynamoDB, Elasticsearch and more.
-
Numeric vectors in Rust
Exact integers and reproducible float sums. An optional SIMD extension runs them up to 90× faster than arrays, in a third of the memory.
03
Performance.
| Server | req/s |
|---|---|
keel run, non-blocking driver | 17,027 |
| FrankenPHP, 64 workers | 5,734 |
3×
the throughput of 64 FrankenPHP workers when requests wait on the database, in about the same memory (244 MB).
Method and caveats| Request | req/s |
|---|---|
| Health check | 51,600 |
| Authenticated read | 23,400 |
| Validation error | 29,700 |
| Create order, with transaction | 13,350 |
2×–6.3×
more requests per second than Laravel Octane, end to end on PostgreSQL (v0.1).
Method and caveats04
A stolen token is worth nothing.
Tokens are bound to the client that holds them. Copy one to another machine and Keel refuses it, then revokes it.
- 1
Issued
Client A signs in and receives a token.
token · active - 2
Bound to client
The token only works from client A.
token · client A - 3
Replayed
Someone copies it and calls the API from client B.
token · from client B - 4
Refused and revoked
The request is refused. The token is revoked for everyone.
token · revoked
05
Five-minute start.
Install the keel command, create an app, serve it. Then follow the tutorial from your first endpoint to production.