Hasura – Deployment

August 11, 20263 min readUpdated 8/21/2026

Hasura is a single stateless binary in a container, which makes deployment simpler than most services and hides the two things that actually bite: connection pooling and metadata consistency across replicas.

The environment that matters

A production configuration is mostly a list of things turned off:

HASURA_GRAPHQL_DATABASE_URL: postgres://hasura_app:...@db.internal:5432/stayhub
HASURA_GRAPHQL_ADMIN_SECRET: ${ADMIN_SECRET}
HASURA_GRAPHQL_JWT_SECRET: '{"type":"RS256","jwk_url":"https://idp.example.com/.well-known/jwks.json"}'
HASURA_GRAPHQL_UNAUTHORIZED_ROLE: anonymous

HASURA_GRAPHQL_ENABLE_CONSOLE: "false"
HASURA_GRAPHQL_DEV_MODE: "false"
HASURA_GRAPHQL_ENABLED_LOG_TYPES: startup, http-log, webhook-log
HASURA_GRAPHQL_CORS_DOMAIN: "https://app.example.com"

HASURA_GRAPHQL_PG_CONNECTIONS: "25"
HASURA_GRAPHQL_PG_TIMEOUT: "180"

Kubernetes

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hasura
spec:
  replicas: 3
  template:
    spec:
      containers:
        - name: hasura
          image: hasura/graphql-engine:v2.42.0
          ports:
            - containerPort: 8080
          readinessProbe:
            httpGet: { path: /healthz, port: 8080 }
            initialDelaySeconds: 10
          livenessProbe:
            httpGet: { path: /healthz, port: 8080 }
            initialDelaySeconds: 30
          resources:
            requests: { cpu: "250m", memory: "512Mi" }
            limits:   { memory: "1Gi" }

The engine is stateless — metadata lives in Postgres, not on disk — so replicas scale horizontally with no coordination. That is the good news.

The pool arithmetic

The bad news is that each replica opens its own pool. Three replicas at twenty-five connections is seventy-five, plus your application, plus migrations, against a max_connections that is often one hundred.

Size it deliberately: replicas × HASURA_GRAPHQL_PG_CONNECTIONS + everything else < max_connections. Autoscaling makes this worse, because the replica count is no longer a number you chose — set the pool from the maximum replica count, not the current one.

Beyond a few replicas, put PgBouncer in transaction mode in front, and then keep Hasura’s own pool small. Two stacked pools each trying to manage the same scarce resource is worse than either alone.

Metadata across replicas

Metadata is in the database, so all replicas read the same thing — but they cache it in memory. Apply a change and the replica you happened to talk to has it; the others do not until they reload.

For a rolling deploy this resolves itself, because new pods read fresh metadata at boot. For a metadata-only change with no image change, it does not. Either apply and then restart the deployment, or call reload_metadata and let it propagate. A brief window where two replicas serve different schemas is otherwise a genuinely confusing bug.

Zero-downtime schema changes

The same expand-and-contract discipline as any database, with metadata as an extra step:

Adding is safe in any order that puts the column before the metadata. Add the column, apply metadata, deploy clients.

Removing must run backwards, over two releases. First remove the field from metadata so no client can request it and deploy that. Only once nothing references it, drop the column. Dropping first leaves metadata referencing a missing column, and the engine boots with that object inconsistent — silently dropping part of your API.

Renaming is add, backfill, migrate clients, remove. There is no atomic rename across a running fleet.

Hasura Cloud

The managed option. You get pooling, autoscaling, metrics, tracing, caching, allow-lists and rate limiting without running any of it — and several of those are Enterprise features you cannot self-host on Community Edition at all.

The trade is the usual one: less operational surface, less control, and a bill that scales with traffic. For a small team whose Hasura is load-bearing, the honest comparison is not “free versus paid” but “paid versus the cost of somebody owning pooling, upgrades and observability”.

Deployment in v3 (DDN)

On the v3 sections. Everything marked v3 (DDN) is taken from the official Hasura DDN documentation as read on 2026-08-21 and was not run locally — it shows configuration, never claimed output. The v2 material was executed against a running engine.

v3 splits the deployment into two halves, and this is the most important thing to understand before committing.

The data plane — the v3 engine and the connectors — is open source and can run on your own infrastructure. The control plane, which handles builds, endpoints, authentication and analytics, is closed source and commercial. There is no v2-style “pull the image and run it, entirely yours” deployment of the whole product.

Private DDN is the offering for running the data plane in your own cloud while the control plane stays managed — the answer for data-residency and network-isolation requirements.

Deployment itself becomes promotion rather than release:

ddn supergraph build create

Each build is immutable with its own endpoint, so “deploying” is pointing traffic at a build you have already tested. Read replicas, incidentally, are included rather than being an Enterprise feature as in v2.

Next

Lessons 18 and 19 are the v3 deep dive; lesson 20 is the interview.