Skip to main content

Benchmarks

These compare ant with GORM v1.31, Bun v1.3, and plain database/sql, doing the same work on the same PostgreSQL 17 in Docker. Plain database/sql stands in for sqlc, whose generated code is a query string and a Scan.

These results came from one run on one laptop in WSL, on 2026-10-31. Read them as a shape, not as a promise. Differences of a few percent are noise. Allocations are stable, and times aren't.

Benchmarkdatabase/sqlantGORMBun
Read 1000 rows1.68 ms1.56 ms3.03 ms2.16 ms
Allocations7,7716,83314,8088,790
Find one row370 µs384 µs390 µs375 µs
Allocations36938941
Filter, sort, limit541 µs537 µs544 µs528 µs
Allocations98178219124
Insert one row2.80 ms2.90 ms2.91 ms3.47 ms
Allocations22767639
Update one column2.86 ms2.96 ms2.94 ms2.96 ms
Allocations8475814

Rows are where a mapper's cost shows. ant reads a row with a compiled list of field pointers, so reading 1000 rows costs about what hand-written Scan calls do, and half what GORM does.

A single row is mostly a network round trip. Every library spends nearly all its time waiting, so the four are within 5% of each other, and one fewer query matters far more. ant allocates more than Bun or plain SQL here, which shows up in a garbage collector's work under load, not in this table.

Writes wait for the disk. The insert and update figures are dominated by the commit.

What ant adds​

Measured with no database involved:

OperationTimeAllocations
Resolving a field probe20 ns0
Building and rendering a query with two conditions, an order, and a limit7.3 µs78

Rendering takes a few microseconds, against a few hundred for the round trip, which is why ant doesn't cache rendered SQL: a cache key would cost about what it saves, and pgx already caches prepared statements per connection.

Run them yourself​

make db-up DATABASES=postgres
cd tools/compare && go test -run '^$' -bench . -benchmem -benchtime 2s