Skip to content

Benchmarks

Kavo ships two benchmark suites in tools/benchmark/. They measure different things and answer different questions — which one to run depends on what you're trying to learn.

Engine micro-benchmarks

Measures raw engine.execute() throughput — no HTTP layer, no NestJS, no ORM. Uses an in-memory fake adapter with 1 000 pre-seeded Todo records. This isolates Kavo's own overhead: config resolution, schema derivation, query normalization, serialization.

bash
pnpm benchmark:engine

Uses vitest bench with the tinybench reporter. Each operation runs sequentially for a default duration, reporting ops/sec, mean latency, and p75/p99 percentiles.

What's measured

OperationDescription
readOneFetch a single record by ID
readManyList with pagination (20 and 100 records)
createOneInsert with JSON body
updateOneFull update
patchOnePartial update
deleteOneDelete

HTTP throughput

Measures full NestJS request lifecycle — HTTP parsing, routing, engine, adapter, serialization, response. Uses autocannon for realistic concurrent load: 50 connections, 10-second duration, pipelining 10.

bash
pnpm benchmark:http

This runs as a regular vitest run (not vitest bench) because it needs to boot a NestJS application. The server starts once in beforeAll, all operations run against it, and the server shuts down in afterAll.

What's measured

RouteOperation
GET /todos?limit=20&sort=-priorityList with pagination + sort
GET /todos/:idSingle fetch by ID
POST /todosCreate with JSON body
PATCH /todos/:idPartial update
DELETE /todos/:idDelete

Both suites use a fake in-memory adapter (InMemoryTodoAdapter). There is no database involved — the bottleneck is the framework, not I/O. For real-world throughput numbers with a database, add a SQLite or PostgreSQL variant.

Results

Measured on Apple M2 Pro, Node v26.5.1.

Engine (ops/sec)

Operationops/secp75 latency
readOne~40,000~25 µs
readMany (20)~37,000~27 µs
readMany (100)~36,000~28 µs
createOne~25,000~40 µs
updateOne~5,000~200 µs
patchOne~5,000~200 µs
deleteOne~1,700~600 µs

HTTP (req/sec)

Routereq/secp50p99
GET /todos~25,80018 ms46 ms
GET /todos/:id~21,50023 ms56 ms
POST /todos~18,40026 ms61 ms
PATCH /todos/:id~17,20027 ms59 ms
DELETE /todos/:id~39,90012 ms23 ms

The gap between engine and HTTP numbers is the NestJS + HTTP overhead per request. DELETE is fastest because it returns no body. Reads and writes that involve serialization/deserialization are slower.

Not part of pnpm check

Benchmarks are opt-in. They are not a CI gate — run them manually when profiling a change, comparing adapter implementations, or investigating a performance regression.