Feature benchmarks
GET / — dispatches a plain request through the router and returns a rendered template — no database access.
GET /items — loads one page of the 1,000 seeded rows through each framework's ORM / Active Record layer: 20 items plus a COUNT for the pagination total.
GET /items-qb — builds the same page of 20 items with each framework's query builder instead of its ORM, so the two data-access styles can be compared directly.
GET /api/items — serves the same page of items as a JSON response rather than HTML, which adds serialization to the ORM work.
GET /features/aop — runs a request through an interceptor pipeline — logging, retry and middleware aspects wrapped around the handler. Only frameworks with an AOP layer take part.
GET /features/cache — reads a COUNT(*) over the 1,000 rows through the framework's cache with a 10-second TTL, so a hit costs no database work and a miss runs the query.
GET /features/db-events — inserts one event row per request and lets the framework's database events fire around that write.
GET /features/events — dispatches an in-process event to registered listeners.
GET /features/validation — validates a payload with the framework's own validator.
GET /features/config — resolves a value from the framework's config repository.
GET /features/request-scoped — resolves a service scoped to the request from the container.
GET /features/rate-limit — checks a cache-backed rate limiter.
Latency by endpoint (ms, trimmed mean — lower is better) (sub-line: boot + handle + post-response cleanup, which sum to the total) — every row and chart point adds the worker's boot (warm recycle), so each number is the full time one request keeps that worker busy
| Request | Workload | Azera | Laravel | Symfony | Spiral | CodeIgniter | CakePHP |
|---|---|---|---|---|---|---|---|
GET / | no DB — routing + template only | 0.017 0.001+0.015+0.001 | 2.73 2.52+0.21+0.00 | 0.620 0.533+0.085+0.002 | 3.76 3.48+0.27+0.01 | 0.466 0.000+0.457+0.009 | 0.136 0.006+0.129+0.001 |
GET /items | 20 of 1000 items (page 1, + COUNT) | 0.143 0.001+0.139+0.003 | 3.25 2.51+0.74+0.00 | 1.07 0.54+0.53+0.00 | 4.03 3.48+0.53+0.02 | 0.761 0.000+0.749+0.012 | 0.488 0.006+0.481+0.001 |
GET /items/1 | 1 item by id | 0.054 0.001+0.051+0.002 | 2.90 2.51+0.39+0.00 | 0.701 0.534+0.165+0.002 | 3.85 3.48+0.36+0.01 | 0.664 0.000+0.652+0.012 | 0.313 0.006+0.306+0.001 |
POST /items | 1 row upserted (sentinel #999999) | 0.110 0.001+0.107+0.002 | 2.93 2.52+0.41+0.00 | 0.789 0.533+0.253+0.003 | 3.90 3.48+0.41+0.01 | 0.737 0.000+0.725+0.012 | 0.423 0.006+0.416+0.001 |
GET /items-qb | 20 of 1000 items (page 1, + COUNT) | 0.095 0.001+0.093+0.001 | 2.94 2.52+0.42+0.00 | 0.770 0.533+0.235+0.002 | 3.86 3.49+0.36+0.01 | 0.747 0.000+0.735+0.012 | 0.287 0.006+0.280+0.001 |
GET /items-qb/1 | 1 item by id | 0.051 0.001+0.049+0.001 | 2.82 2.51+0.31+0.00 | 0.669 0.533+0.134+0.002 | 3.81 3.48+0.32+0.01 | 0.656 0.000+0.644+0.012 | 0.226 0.006+0.219+0.001 |
POST /items-qb | 1 row upserted (sentinel #999997) | 0.085 0.001+0.083+0.001 | 2.91 2.51+0.40+0.00 | 0.807 0.533+0.271+0.003 | 3.85 3.49+0.35+0.01 | 0.849 0.000+0.836+0.013 | 0.295 0.006+0.288+0.001 |
GET /api/items | 20 of 1000 items as JSON | 0.041 0.001+0.039+0.001 | 3.13 2.52+0.61+0.00 | 0.763 0.534+0.227+0.002 | 3.90 3.49+0.40+0.01 | 0.610 0.000+0.600+0.010 | 0.265 0.006+0.258+0.001 |
GET /api/items/1 | 1 item by id as JSON | 0.039 0.001+0.037+0.001 | 2.91 2.51+0.40+0.00 | 0.678 0.533+0.143+0.002 | 3.82 3.49+0.32+0.01 | 0.577 0.000+0.566+0.011 | 0.233 0.006+0.226+0.001 |
POST /api/items | 1 row upserted (sentinel #999998) | 0.056 0.001+0.053+0.002 | 2.86 2.51+0.35+0.00 | 0.772 0.534+0.236+0.002 | 3.85 3.48+0.36+0.01 | 0.651 0.000+0.640+0.011 | 0.320 0.006+0.313+0.001 |
GET /features/aop | no DB — interceptor pipeline | 0.130 0.001+0.128+0.001 | 2.84 2.52+0.32+0.00 | 0.759 0.534+0.223+0.002 | 4.00 3.48+0.51+0.01 | — | — |
GET /features/cache | COUNT(*) of 1000 rows, cached 10s (miss = query) | 0.014 0.001+0.012+0.001 | 2.76 2.52+0.24+0.00 | 0.618 0.533+0.083+0.002 | 3.80 3.48+0.31+0.01 | 0.414 0.000+0.406+0.008 | 0.106 0.006+0.099+0.001 |
GET /features/log | no DB — buffered log handlers | 0.014 0.001+0.012+0.001 | 2.73 2.51+0.22+0.00 | 0.614 0.533+0.079+0.002 | 3.79 3.48+0.30+0.01 | — | — |
GET /features/retry | no DB — retry policy | 0.011 0.001+0.009+0.001 | 2.74 2.51+0.23+0.00 | 0.620 0.534+0.084+0.002 | 3.80 3.48+0.31+0.01 | — | — |
GET /features/pipeline | no DB — middleware pipeline | 0.015 0.001+0.013+0.001 | 2.74 2.52+0.22+0.00 | 0.617 0.534+0.081+0.002 | 3.80 3.48+0.31+0.01 | — | — |
GET /features/db-events | 1 event row INSERTed per request | 0.049 0.001+0.047+0.001 | 2.91 2.52+0.39+0.00 | 0.736 0.534+0.200+0.002 | 3.97 3.48+0.48+0.01 | 0.742 0.000+0.730+0.012 | 0.259 0.006+0.252+0.001 |
GET /features/events | no DB — in-process listeners | 0.040 0.001+0.038+0.001 | 2.81 2.51+0.30+0.00 | 0.649 0.533+0.114+0.002 | 3.85 3.48+0.36+0.01 | 0.703 0.000+0.691+0.012 | 0.151 0.006+0.144+0.001 |
GET /features/validation | no DB — validator run | 0.020 0.001+0.018+0.001 | 3.36 2.51+0.85+0.00 | 0.729 0.534+0.193+0.002 | 3.83 3.49+0.33+0.01 | 0.684 0.000+0.671+0.013 | 0.189 0.006+0.182+0.001 |
GET /features/config | no DB — config lookup | 0.010 0.001+0.008+0.001 | 2.74 2.52+0.22+0.00 | 0.616 0.533+0.081+0.002 | 3.79 3.48+0.30+0.01 | 0.423 0.000+0.415+0.008 | 0.095 0.006+0.088+0.001 |
GET /features/request-scoped | no DB — scoped service resolve | 0.010 0.001+0.008+0.001 | 2.73 2.51+0.22+0.00 | 0.614 0.533+0.079+0.002 | 3.81 3.48+0.32+0.01 | 0.407 0.000+0.399+0.008 | 0.094 0.006+0.087+0.001 |
GET /features/rate-limit | no DB — cache-backed limiter | 0.011 0.001+0.009+0.001 | 2.76 2.51+0.25+0.00 | 0.623 0.533+0.088+0.002 | 3.82 3.48+0.33+0.01 | 0.414 0.000+0.406+0.008 | 0.106 0.006+0.099+0.001 |