Database
| Variable | Required | Default | Description |
|---|---|---|---|
| DATABASE_URL | Yes | - | PostgreSQL connection string |
| PGRST_DB_SCHEMAS | No | public | Schemas to expose (comma-separated) |
| PGRST_DB_ANON_ROLE | No | - | Role for unauthenticated requests |
| PGRST_DB_POOL_SIZE | No | 10 | Connection pool size |
Authentication
| Variable | Required | Default | Description |
|---|---|---|---|
| PGRST_JWT_SECRET | No | - | JWT signing secret |
| PGRST_JWT_SECRET_IS_BASE64 | No | false | If secret is base64 encoded |
| PGRST_JWT_AUD | No | - | Required JWT audience claim |
| PGRST_JWT_ROLE_CLAIM_KEY | No | role | Claim key for role |
Server
| Variable | Required | Default | Description |
|---|---|---|---|
| PGRST_SERVER_HOST | No | 127.0.0.1 | Bind address |
| PGRST_SERVER_PORT | No | 3000 | Port to listen on |
| PGRST_SERVER_CORS_ORIGINS | No | * | CORS allowed origins |
Limits
| Variable | Required | Default | Description |
|---|---|---|---|
| PGRST_MAX_ROWS | No | unlimited | Maximum rows returned by one request; caps requests with no limit |
| PGRST_MAX_BODY_SIZE | No | 10485760 | Max request body in bytes |
Compatibility
| Variable | Required | Default | Description |
|---|---|---|---|
| PGRST_COMPAT_MODE | No | false | PostgREST 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
| Variable | Required | Default | Description |
|---|---|---|---|
| PGRST_HASURA_ADMIN_SECRET | No | - | 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_ROLE | No | - | 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
| Variable | Required | Default | Description |
|---|---|---|---|
| PGRST_GRAPHQL_METADATA | No | - | 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
| Variable | Required | Default | Description |
|---|---|---|---|
| PGRST_LOG_LEVEL | No | info | Log level (error, warn, info, debug) |
| RUST_LOG | No | - | 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:
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:
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
# 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