DocsConfiguration

Configuration

All environment variables and configuration options for Postrust.

Database

VariableRequiredDefaultDescription
DATABASE_URLYes-PostgreSQL connection string
PGRST_DB_SCHEMASNopublicSchemas to expose (comma-separated)
PGRST_DB_ANON_ROLENo-Role for unauthenticated requests
PGRST_DB_POOL_SIZENo10Connection pool size

Authentication

VariableRequiredDefaultDescription
PGRST_JWT_SECRETNo-JWT signing secret
PGRST_JWT_SECRET_IS_BASE64NofalseIf secret is base64 encoded
PGRST_JWT_AUDNo-Required JWT audience claim
PGRST_JWT_ROLE_CLAIM_KEYNoroleClaim key for role

Server

VariableRequiredDefaultDescription
PGRST_SERVER_HOSTNo127.0.0.1Bind address
PGRST_SERVER_PORTNo3000Port to listen on
PGRST_SERVER_CORS_ORIGINSNo*CORS allowed origins

Limits

VariableRequiredDefaultDescription
PGRST_MAX_ROWSNounlimitedMaximum rows returned by one request; caps requests with no limit
PGRST_MAX_BODY_SIZENo10485760Max request body in bytes

Compatibility

VariableRequiredDefaultDescription
PGRST_COMPAT_MODENofalsePostgREST compatibility mode: serves the REST API at the root (/rpc/fn, /table) in addition to /api, and un-wraps RPC responses to PostgREST's shape. Object key order is a build-time choice, not covered by this setting - see below. Alias: POSTRUST_COMPAT_MODE

Hasura Authentication

VariableRequiredDefaultDescription
PGRST_HASURA_ADMIN_SECRETNo-Shared secret authenticating an administrator. A caller holding it may ask to be treated as any role. Alias: HASURA_GRAPHQL_ADMIN_SECRET
PGRST_HASURA_UNAUTHORIZED_ROLENo-Role for a request nothing authenticated. Unset means such a request is refused, which is the default. Alias: HASURA_GRAPHQL_UNAUTHORIZED_ROLE

GraphQL Names and Permissions

VariableRequiredDefaultDescription
PGRST_GRAPHQL_METADATANo-Names for tables, columns, root fields, relationships and computed fields that the schema cannot supply; which root a function is exposed on; and what each role may do with each table. A JSON document, or a path to a file holding one. Unset means every name is derived and there is no permission layer. Also read as PGRST_GRAPHQL_NAMES, which is what it was called when names were all it carried.

Logging

VariableRequiredDefaultDescription
PGRST_LOG_LEVELNoinfoLog level (error, warn, info, debug)
RUST_LOGNo-Detailed tracing configuration

Key ordering is a build-time choice

Postrust returns the keys within each object alphabetically. PostgREST returns them in the order of the select list. That difference is decided when the binary is compiled rather than at run time, because it depends on the map type holding a JSON object, so PGRST_COMPAT_MODE cannot switch it on. It is a Cargo feature:

Terminal
cargo build --release -p postrust-server --features compat-key-order

# Default build
curl 'localhost:3000/api/users?select=status,name,id&limit=1'
# -> [{"id":1,"name":"Alice","status":"active"}]

# With compat-key-order
curl 'localhost:3000/api/users?select=status,name,id&limit=1'
# -> [{"status":"active","name":"Alice","id":1}]

It is off by default because it is not free. Measured by running both builds as containers against the same database and alternating between them, a three-column response cost 1% and an eight-column response 15%: for objects this small a few short string comparisons beat hashing every key, so the sorted map is genuinely the faster one. Turn it on when byte-level compatibility matters more.

Running with PGRST_COMPAT_MODE=true on a binary built without the feature logs a warning at startup, so the difference is not left to be found by diffing responses.

Hasura authentication

The GraphQL surface reads Hasura’s headers, so a deployment migrating from Hasura keeps sending what it already sends. Both spellings of each variable are read, so an existing HASURA_GRAPHQL_* environment needs no renaming.

Set the secret, and a caller that holds it is an administrator — and an administrator may ask to be treated as someone else:

bash
curl localhost:3000/v1/graphql \
  -H 'X-Hasura-Admin-Secret: shh' \
  -H 'X-Hasura-Role: user' \
  -H 'X-Hasura-User-Id: 1' \
  -d '{"query":"{ article { id title } }"}'

That request is answered as user, and x-hasura-user-id becomes a session variable a row-level policy reads as current_setting('hasura.user_id') — or that a function taking hasura_session json receives whole. A Hasura role is not a database role: Artist and anonymous need not exist in any catalogue.

Choosing a role with a token

A token that allows more than one identity carries x-hasura-default-role — who the caller is when it asks for nothing — beside x-hasura-allowed-roles, the list it may ask for instead. The asking is done with an X-Hasura-Role header, and no admin secret is needed for it. That list sits inside the signature, so a caller may choose among the identities it was issued and cannot add one. Asking for a role the token does not list is refused. A token carrying no list allows only the role it already names.

One place this deliberately differs from Hasura

Hasura with no admin secret configured treats every caller as an administrator — which also means an unsecured deployment lets any caller name its own role and its own identity. Postrust does not: with no secret configured, x-hasura-* headers carry no weight and session variables come only from a verified token. A policy reading a value the caller chose is not a policy, and the failure is silent — the query succeeds, against the wrong rows.

See Hasura conformance for how much of the dialect this covers, measured.

Example Configuration

.env
# Required
DATABASE_URL=postgres://user:password@localhost:5432/mydb

# Authentication
PGRST_DB_ANON_ROLE=web_anon
PGRST_JWT_SECRET=your-secret-key-at-least-32-characters

# Hasura-dialect GraphQL at /v1/graphql
PGRST_HASURA_ADMIN_SECRET=shh
PGRST_HASURA_UNAUTHORIZED_ROLE=anonymous

# Server
PGRST_SERVER_HOST=0.0.0.0
PGRST_SERVER_PORT=3000
PGRST_SERVER_CORS_ORIGINS=https://myapp.com

# Limits
PGRST_MAX_ROWS=100
PGRST_LOG_LEVEL=info