Postrust vs PostGraphile
PostGraphile generates a GraphQL API from a PostgreSQL schema and puts most of its effort into the quality of that schema and the plan behind it. V5's Gra*fast* engine plans a query once and executes it with far fewer round trips than a naive resolver tree.
It is also the most customisable of these tools. If you want to reshape the generated schema, PostGraphile expects that and has a plugin system built for it.
- PostGraphile is written in
- TypeScript / Node.js
- Licence
- MIT
- Version compared
- V5
- Their site
- postgraphile.org
Feature comparison
Where a capability has a condition attached, the condition is in the cell.
| Feature | Postrust | PostGraphile |
|---|---|---|
| GraphQL from the schema | Yes | Yes |
| REST API | Yes, PostgREST-compatible | Not supported |
| Subscriptions | Over LISTEN/NOTIFY | Built in over LISTEN/NOTIFY; you define the fields |
| Schema customisation | Not extensible at runtime | Plugin system, the main design goal |
| Relay support | No | Yes |
| Permissions | PostgreSQL roles and RLS | PostgreSQL roles and RLS |
| Runtime | Single static binary | Node.js |
| Custom logic | Rust handlers, or SQL functions | TypeScript plugins, or SQL functions |
| License | MIT | MIT |
Measured performance
Produced by scripts/bench-compare.sh, which starts both servers as containers against the same database and runs the same load against each. Where PostGraphile is faster, that is what the table says.
GraphQL
| Scenario | Postrust req/s | PostGraphile req/s | Postrust p95 | PostGraphile p95 | Difference |
|---|---|---|---|---|---|
| single row by primary key | 12,440 | 10,231 | 5.1 ms | 6.7 ms | 1.2× faster |
| 25-row page | 8,477 | 6,593 | 7 ms | 10.2 ms | 1.3× faster |
| 25-row page + embed | 5,193 | 3,495 | 11.4 ms | 16.5 ms | 1.5× faster |
Image size and memory
| Postrust | PostGraphile | |
|---|---|---|
| Container image, on disk | 168MB | 2.27GB |
| Memory, before serving a request | 1.9 MB | 110.1 MB |
| Memory, after the benchmark | 14.8 MB | 242.1 MB |
Memory is resident set size, read the same way for every tool. Image sizes are for the Debian-based build these figures come from. The Alpine build of the same code is 31.7MB.
How this was measured
- Every server runs as a container on one docker network against the same PostgreSQL instance and the same dataset. No tool gets to skip container overhead.
- Each tool keeps its own default connection pool and worker settings. Tuning one and not the others measures the tuning, not the tool.
- Requests are expressed in each tool's own dialect, because the dialects differ. The work asked of PostgreSQL is the same.
- Every target is warmed before any of them is measured, and the database cache is populated first, so no tool pays to warm the cache for the ones measured after it.
- Each figure is the median of several runs rather than the best of them, because a best-of-N reports whichever tool got the quietest moment on the machine.
- These are single-machine numbers from a laptop. They are useful for comparing the tools against each other, not for capacity planning.
Darwin 25.2.0 arm64 · PostgreSQL postgres:16 · bench_items 100000 rows, bench_reviews 300000 rows · 3000 requests at concurrency 50, median of 5 runs after 500 warm-up requests. Full benchmark method
When PostGraphile is the better choice
- You want to shape the GraphQL schema rather than accept what was generated. This is PostGraphile's central strength and Postrust has no answer to it.
- Your team writes TypeScript and wants API extensions in the same language as the rest of the stack.
- You want a Relay-compliant schema, or the connection and node-id conventions that come with it.
- GraphQL is the API and REST is not needed.
When Postrust fits better
- You want one process serving both REST and GraphQL.
- You would rather deploy a static binary than a Node runtime.
- The generated schema is fine as generated and extensibility is not what you are paying for.
Questions
Why do the GraphQL queries differ between the two in the benchmark?
Field names are inflected differently: Postrust exposes bench_items where PostGraphile exposes allBenchItems with a nodes wrapper. The request asks PostgreSQL for the same rows either way, and both queries are in the benchmark script.
Is Gra*fast* faster than what Postrust does?
Look at the measured table on this page rather than taking either project's word for it. Gra*fast* is a serious piece of engineering and the numbers are the numbers.
Try it against your own schema
Point it at a database and see what it generates. That is a shorter path than reading a comparison table.