PRODSovereign European BaaS platformOpen Dashboard →

Engineering · 10 min read

pg_graphql vs Hasura and PostGraphile on Postgres

Affane Daylami · Fondateur · July 31, 2026

Back to blog

A GraphQL API on Postgres means very different things depending on the tool. PostGraphile deploys a separate Node server. Hasura deploys a GraphQL engine in front of your database. pg_graphql runs in Postgres — this is the approach taken by Aurabase. This is not an implementation detail: it changes what you need to host, secure and maintain.

This English text was generated automatically from the French original and has not been reviewed yet.

pg_graphql is an open source Postgres extension maintained by Supabase — it is not an Aurabase invention. What we have built is its native and opt-in integration into the platform: a box to check per project, not a service to provision. This post details the actual architecture, shows how to enable it, and honestly compares the trade-offs against Hasura and PostGraphile v5.

The essentials
  • pg_graphql runs in Postgres as an SQL extension — no separate GraphQL server to deploy, unlike Hasura and PostGraphile.
  • The wrapper function provided by Aurabase is SECURITY INVOKER: your RLS policies apply automatically, without a second permission system to maintain in parallel.
  • Opt-in activation per project only — aura projects graphql-enable or the Studio — never activated by default, on any project.
  • Hasura officially refocused its focus on PromptQL and AI agents in June 2025, without abandoning its GraphQL engine.
  • PostGraphile v5 went generally available on March 24, 2026 — a direct and active competitor, not a dormant project.
#
Overview

pg_graphql, in one sentence

pg_graphql introspects your SQL schema and generates a GraphQL schema conforming to the Relay convention — <table>Collection, edges, node, filters by column type, pagination by cursor. No SDL to write or maintain by hand: the GraphQL schema follows your Postgres schema.

The point that matters for the architecture: this schema generator lives inside the database, as an SQL function, not as an HTTP process next to it. Aurabase pins the 1.6.1 version of the extension (released May 7, 2026) in its Postgres image — the same official .deb package as distributed by Supabase. It is installed both on the shared cluster and on the dedicated Postgres instances.

If you come from Supabase, where pg_graphql has been natively enabled for a long time, the logic will be familiar to you. Our detailed comparison and our migration guide cover the rest of the RLS schema and policies, which remain the same.

#
Context 2026

What has changed at Hasura and PostGraphile

Neither of the two historical competitors of “instant GraphQL on Postgres” has disappeared. Their positioning has shifted, and an updated article should reflect that rather than citing the state of two years ago.

Hasura published a post in June 2025 with the explicit title, “From GraphQL to PromptQL: A New Chapter Begins”, signed by its co-founder Tanmai Gopal. The message: the company is refocusing its roadmap on PromptQL, a data access layer designed for AI agents. The GraphQL engine is not removed - Hasura's home page still presents it as "battle-tested" - but it is no longer the priority message.

PostGraphile, for its part, did the opposite. Its version 5, in development since 2023 in the form of betas, became generally available on March 24, 2026, with a new query planning engine called Grafast. This is not a project that is running out of steam: the last release, 5.1.4, dates from August 5, 2026. The npm package counted 119,230 downloads in the week of August 16 to 22, 2026 alone (npm registry, consulted August 23, 2026).

Astuce

Practical consequence: the real vacant space is not “GraphQL on Postgres, no one touches it” — it is the specific GraphQL zero-config slot, activated in one command, with no service to host. Hasura moves away from it by strategic choice; PostGraphile has never targeted it, its model remains “Node.js library to integrate yourself”.

#
Architecture

Where each solution actually turns

The difference that structures everything else — operating cost, attack surface, latency — is where the GraphQL engine runs.

Where it turnsSQL extension, in PostgresSeparate GraphQL server (Go), in front of PostgresNode.js library/server, ahead of Postgres
Deployment requiredNone — activated by a project flagYes — host and scale the Hasura engineYes — host the Node process or integrate it with your server
Permissions modelLegacy Postgres RLS (SECURITY INVOKER)Hasura's own permissions system, per role/tableRLS Postgres via pgSettings — native delegation too
Introspection by defaultDisabledDepending on engine configurationDepending on server configuration
Positioning 2026Native option of a Postgres BaaSRefocused on PromptQL/IA since June 2025GA v5 since March 2026, active project
AURABASEHASURAPOSTGRAPHIC V5

To be honest: PostGraphile also delegates authorization to Postgres via pgSettings and role switching — native RLS is not exclusive to pg_graphql. What remains different is who hosts and configures this bridge: at PostGraphile, it's you; at Aurabase, this is already done.

#
Under the hood

How Aurabase activates pg_graphql on a project

Activation is opt-in, per project, and reserved for Postgres engine projects — a MongoDB project refuses the request (GRAPHQL_UNSUPPORTED_ENGINE), pg_graphql being a Postgres extension with no equivalent on the other engine.

Via the CLI or by directly calling the management plan:

terminalbash
# Idempotent: recalling an already activated project does not recreate anything
aura projects graphql-enable <project_id>

# HTTP equivalent (management plane, JWT console)
curl -X POST "$AURA_CONTROL_URL/v1/control/projects/$PROJECT_ID/graphql/enable" \
  -H "Authorization: Bearer $CONSOLE_JWT"

On the server side, the call executes a graphql_enable job that the provisioner executes in a single transaction: installation of the extension, creation of the graphql() function in your schema, GRANTs to the application roles. If a step fails, everything is canceled — never a wrapper installed halfway, and graphql_enabled only moves to true after complete success.

It works both on the shared Postgres cluster and on a dedicated CNPG instance per project — two different Postgres images, but the same extension mechanism. On dedicated instances, the extension is installed via the declarative manifest of the CNPG operator rather than direct SQL — a recent correction. A dedicated cluster runs without application superuser access, and pg_graphql requires precisely this privilege for its CREATE EXTENSION.

From the Studio, the same flow goes through the Table Configuration tab. A button there activates the extension at the project level — the same HTTP call as above, with polling until convergence. A second control then sets a @graphql directive per table, to activate or not totalCount and the aggregation fields on its GraphQL collection, without leaving the editor.

Single command view: activation → provisioning job threaded (idempotent, no-op if already in flight) → DDL transaction (extension, wrapper function, GRANTs) → flag graphql_enabled set only after complete success → requests possible via /rpc/graphql.

#
Security

Legacy RLS, not a second system to maintain

The function set by Aurabase is SECURITY INVOKER — default behavior of Postgres, explained so that a future refactor does not change it by accident. It runs with the privileges of the actual caller (aura_anon, aura_authenticated or aura_service_role, depending on the JWT claim), so your RLS policies apply exactly as for a REST request.

Why not SECURITY DEFINER

A SECURITY DEFINER function would bypass the entire RLS — checked internally: calling graphql.resolve under superuser connection without changing application role returns the rows of all owners, RLS or not. Exactly the cross-tenant risk that this choice avoids.

At Hasura, the architecture is different by construction: the engine converts each GraphQL query into an SQL query constrained by permission rules specific to Hasura. These rules are defined per role and per table in its own layer — a parallel system to the Postgres RLS, not a delegation to it. Two places to audit access rules, instead of just one.

Introspection ({ __schema { ... } }) remains disabled by default on each Aurabase project — a posture consistent with the rest of the platform. It can be activated by schema via COMMENT ON SCHEMA if a tool like Apollo Studio or graphql-codegen needs it.

#
Tutorial

Enable then query your GraphQL API

Once graphql_enabled to true, no dedicated /graphql route appears on the gateway. The request goes through the generic RPC proxy, just like any Postgres function called from the SDK.

query.shbash
curl -X POST "$AURA_URL/v1/db/$PROJECT_ID/rpc/graphql" \
  -H "apikey: $AURA_ANON_KEY" -H "Authorization: Bearer $JWT" \
  -H "Content-Type: application/json" \
  -d '{"query":"query { postsCollection(first: 10, filter: { published: { eq: true } }) { edges { node { id title created_at } } } }"}'

The response follows the GraphQL spec — { data, errors } — without additional Aurabase wrapping: the gateway detects that the targeted RPC is graphql and does not rewrap it, unlike an ordinary RPC. A standard GraphQL client (Apollo, urql, graphql-request) consumes the output as is.

Two settings are set by default upon activation, via a @graphql directive on the diagram: max_rows: 1000 and inflect_names: true. pg_graphql caps by default at 10,000 rows per collection — without first:, a large table can saturate memory. inflect_names gives readable type names rather than the raw snake_case of SQL tables.

#
Limits

What pg_graphql doesn't do (yet)

To be documented rather than hidden, in the spirit of this blog.

  • No native GraphQL subscriptions. pg_graphql covers queries and mutations, not real-time subscriptions — this is a limitation of the extension itself, not an Aurabase omission. Real-time Aurabase exists, but through a separate channel (postgres_changes), not a GraphQL subscriptions bridge.
  • No declarative actions à la Hasura. The “business webhook connected to a GraphQL mutation” model has no direct equivalent — on Aurabase, this logic goes through a Postgres function or an Edge Function, not through a dedicated GraphQL configuration.
  • Reserved for the Postgres engine. A MongoDB project cannot enable this — no workaround intended.
Info

Why activation remains opt-in rather than default: The GRANT/Roles area of the tenant database has a documented history of regressions. This is enough to justify that no functionality touches it without explicit validation, project by project, before considering a broader defect.

#
Decision

Aurabase, Hasura or PostGraphile: depending on your context

All three options are legitimate — the right choice depends on what you already have and what you're looking to avoid.

  • pg_graphql on Aurabase — if your RLS database and policies already live on Aurabase and you want a second way to query it without additional services to monitor.
  • Hasura — if you federate multiple data sources (not just Postgres) behind a single GraphQL schema, or if PromptQL and its AI agent approach fit your roadmap.
  • PostGraphile v5 — if you want fine control over the schema generated via its plugin system, and you already run a Node.js server into which to integrate it.

For full query syntax — filters by column type, orderBysorting, pagination by cursor, insertInto<Table>Collection mutations — see the official pg_graphqldocumentation. The Aurabase GraphQL documentation, below, also details the full cycle.

READY TO DEPLOY?

Your backend in five minutes.

No credit card required · 500 MB free · 50,000 MAU