Which languages are PostgreSQL API servers written in, and does it matter?

Most established PostgreSQL API servers are written in Haskell (PostgREST, Hasura v2) or TypeScript on Node.js (PostGraphile); newer ones are written in Rust (Postrust, the Hasura DDN v3 engine, and pg_graphql as a PostgreSQL extension) or Go (GraphJin). For per-request speed the language matters less than how the server turns a request into SQL and how many round trips it makes to the database. The runtime matters most for memory footprint, cold starts and how the server is deployed.

Which languages are the established PostgreSQL API servers written in?

Haskell, TypeScript on Node.js, Rust and Go. The two longest-established, PostgREST and Hasura v2, are Haskell; PostGraphile is TypeScript; of the newer tools listed here, three are Rust and one is Go.

ToolLanguage / runtimeAPI surfaceHow it shipsLicence
PostgRESTHaskellRESTSingle binary, or a container imageMIT
Hasura v2HaskellGraphQLContainerApache 2.0 (v2 core engine)
Hasura DDN (v3 engine)RustGraphQLEngine plus a data connector per source; the PostgreSQL connector is also RustApache 2.0 repository
PostGraphile V5TypeScript on Node.jsGraphQLnpm package on a Node.js runtimeMIT
pg_graphqlRust, built with pgrxGraphQLPostgreSQL extension, runs inside the databaseApache 2.0
GraphJinGoGraphQLGo binary or libraryApache 2.0
SupabaseA platform of services (PostgREST, GoTrue, Realtime)REST through PostgREST; GraphQL through a Postgres extensionManaged, or self-host the stackApache 2.0
PostrustRustREST (PostgREST dialect) and GraphQL (Hasura dialect)Single static binary, container, AWS Lambda, Cloudflare WorkersMIT

Versions are the ones the comparison pages describe: PostgREST v16.1, Hasura v2.50.1 and PostGraphile V5. Hasura recommends DDN for new projects, and it is a different architecture from v2 rather than a rewrite of the same server. For how the GraphQL tools differ in features rather than language, see PostgreSQL GraphQL tools compared.

Which PostgreSQL API tools are written in Rust?

Postrust, the Hasura DDN v3 engine and pg_graphql. They use Rust in three quite different shapes.

  • Postrust is a standalone server built on Axum and SQLx. One binary serves a REST API in PostgREST’s dialect and a GraphQL API in Hasura’s, and the same code runs as a server, in a container, on AWS Lambda and on Cloudflare Workers.
  • Hasura DDN’s v3 engine does not query the database itself. It sends an intermediate query to a data connector, and the PostgreSQL connector (ndc-postgres) is Rust too.
  • pg_graphql is not a server at all. It is a PostgreSQL extension built with the pgrx framework, so the GraphQL query is resolved inside the database and something else has to put it on HTTP. On Supabase, that is PostgREST.

Where does the time in an API request actually go?

Mostly into the database: the network round trip to PostgreSQL and the query it runs. The server’s own work — parsing the request, checking a token, building SQL, writing JSON — is usually the smaller part, whatever language it is written in.

Postrust’s Cloudflare Workers documentation measures this directly. With the round trip to the database set exactly, by delaying every packet the database sends, a read from the Postrust server took 1.0 ms with no added delay, 34 ms with 5 ms added, 124 ms with 20 ms and 364 ms with 60 ms. The server did not get slower; it waited on the database once per statement. On Cloudflare through Hyperdrive, a read with the Worker and the database both in Singapore took 41 ms, and 255 ms with the database in Delhi, about 75 to 80 ms away.

So the decisions that move latency most are architectural: how many statements a request needs, whether they are sent together, and what the generated SQL asks PostgreSQL to do. Hasura v2 compiles a GraphQL query into SQL rather than resolving it field by field, and PostGraphile V5’s Grafast engine plans a query once and executes it with far fewer round trips than a naive resolver tree. A server that issues one query where another issues ten will usually win, in any language.

The benchmark page makes the same point about its own results. Postrust and PostgREST each issue exactly one query per request there, but Postrust sends a plain parameterised SELECT and renders the JSON itself, while PostgREST wraps the query in a CTE, computes a count and builds the JSON inside PostgreSQL on every request. Much of the measured difference is where each design does its work, not the speed of the HTTP layer. Connection pooling belongs in the same category: Postrust keeps a pool open (default size 10), and a server that opened a connection per request would pay for it in round trips.

How much memory and disk does each runtime use?

This is where the runtime shows most plainly. Haskell, Node.js and Rust programs carry different amounts of runtime with them, and that is visible in memory use and container image size.

ServerContainer image, on diskMemory before the first requestMemory after the benchmark
Postrust149 MB3.0 MB17.1 MB
PostgREST v16.127 MB5.2 MB51.0 MB
Hasura v2.50.1602 MB166.1 MB202.5 MB
PostGraphile V52.29 GB54.7 MB215.3 MB

Resident set size, read the same way for every server, from Postrust’s benchmark harness on AMD EPYC 9255 24-Core Processor with postgres:16, Debian-based images. The Alpine build of Postrust is a 34.9 MB image. Image size depends heavily on the base image: PostgREST’s official image is the smallest here.

The Postrust binary itself is 3,070,080 bytes (2.93 MiB) with default features and 5,220,864 bytes (4.98 MiB) with the admin UI, as shipped. A compiled language with no garbage-collected runtime starts small and stays close to what it is actively using; the figures above are one measurement of that, on one host, not a capacity plan.

Does the language matter for AWS Lambda and Cloudflare Workers?

More than anywhere else. Serverless platforms start instances on demand, cap memory and CPU per request, and limit what can be uploaded, so a small self-contained binary is a better fit than a server that needs a language runtime installed and warmed up.

Postrust treats both as first-class deployment targets. On AWS Lambda the function runs the server’s own router, so REST, GraphQL, JWT authentication and row-level security behave identically; the schema cache loads once per sandbox, in the init phase, so warm invocations do not pay for it. On Cloudflare Workers it runs the server’s own REST request pipeline compiled to WebAssembly, reaching PostgreSQL through Hyperdrive. That bundle is 2.7 MB of WebAssembly, 0.94 MB gzipped, within the free plan’s 3 MB.

Cold starts are still real, and again the database dominates them. The first request in a new Worker isolate took about 440 ms with the database in Singapore when the isolate had to read the catalog itself, and about 230 ms with the schema cache in Workers KV; with the database in Delhi, about 2,000 ms against about 400 ms. That first request uses 60 to 250 ms of CPU, mostly starting the WebAssembly, against 4 to 11 ms for later ones.

How do the concurrency models differ?

All of these servers handle many requests at once without a thread per request, so for a database-bound API none of the models is a bottleneck by itself.

Haskell’s GHC runtime schedules lightweight threads across cores. Node.js runs JavaScript on a single-threaded event loop, so CPU-heavy work in one request delays the others unless the deployment runs several processes. Rust servers such as Postrust use async tasks on a multi-threaded runtime (Tokio, under Axum). Go uses goroutines. In every case the useful limit is usually the connection pool and the database behind it, not the scheduler.

How much should the language weigh when choosing a PostgreSQL API server?

Less than features, maturity and fit, unless footprint or serverless is a hard requirement. PostgREST and Hasura have years of production use behind them; PostGraphile is the most customisable; Supabase is a whole platform. Choose on those grounds first.

The language becomes the deciding factor when the deployment shape is: a small container, many replicas, a function that must start quickly, or an edge runtime with a size limit. That is the case Postrust was built for. The PostgREST, Hasura, PostGraphile and Supabase comparisons set out where each of those tools is the better choice.

Questions people ask: Languages Used to Build PostgreSQL API Servers

Which PostgreSQL API servers are written in Rust?

Postrust (REST and GraphQL from one binary), the Hasura DDN v3 engine, and pg_graphql, which is a PostgreSQL extension built with pgrx rather than a separate server. Hasura's PostgreSQL data connector for DDN is also written in Rust.

What language is PostgREST written in?

PostgREST is written in Haskell and released under the MIT licence. It ships as a single binary and as a container image.

Is a Rust PostgreSQL API server automatically faster than a Haskell or Node.js one?

Not automatically. Most of a request's time is usually spent on the database round trip and in the SQL the server generates, so query design and the number of round trips tend to matter more than the language. The language shows up most clearly in memory use, start-up time and how the server is packaged.

Why does the runtime matter for AWS Lambda and Cloudflare Workers?

Serverless platforms start new instances on demand and limit memory and CPU per request, so a small binary with no runtime to boot fits them well. Postrust runs on AWS Lambda through a native adapter and on Cloudflare Workers as WebAssembly, with the Worker bundle at 2.7 MB, 0.94 MB gzipped.

Does Supabase use a Rust API server?

Supabase's REST API is PostgREST, which is written in Haskell. Its GraphQL API comes from pg_graphql, a PostgreSQL extension written in Rust.