Introduction
Hasura instantly turns a PostgreSQL database into a GraphQL API while providing fine-grained control over permissions and business logic. In 2026, enterprises demand enterprise deployments with custom Actions to integrate microservices and asynchronous processing. This tutorial covers advanced deployment, row-level permission configuration, and implementation of secure Actions. You will learn how to manage events and monitor performance in production. Each step includes concrete examples and complete configuration files.
Prerequisites
- Docker and Docker Compose v2.20+
- PostgreSQL 15+ with extensions
- Hasura Enterprise or Cloud account
- Solid knowledge of GraphQL and TypeScript
- Node.js 20+ for Action handlers
Enterprise Docker Deployment
version: '3.8'
services:
postgres:
image: postgres:15
environment:
POSTGRES_PASSWORD: securepass
POSTGRES_DB: hasura
volumes:
- pgdata:/var/lib/postgresql/data
hasura:
image: hasura/graphql-engine:v2.36.0-enterprise
ports:
- "8080:8080"
environment:
HASURA_GRAPHQL_DATABASE_URL: postgres://postgres:securepass@postgres:5432/hasura
HASURA_GRAPHQL_ENABLE_CONSOLE: "true"
HASURA_GRAPHQL_ADMIN_SECRET: myadminsecret
HASURA_GRAPHQL_UNAUTHORIZED_ROLE: anonymous
depends_on:
- postgres
volumes:
pgdata:This file deploys PostgreSQL and Hasura Enterprise with the required production variables. The anonymous role is set for public queries while protecting the admin secret.
Initial Metadata Configuration
After startup, connect to the Hasura console and create the tables. Then import the metadata for relationships and basic permissions. This establishes the foundation before adding Actions.
Advanced Permission Definition
-
table:
schema: public
name: articles
select_permissions:
-
role: user
permission:
columns: ["id", "title", "content"]
filter:
author_id:
_eq: "X-Hasura-User-Id"This configuration applies a row-level filter based on the X-Hasura-User-Id header. Only articles belonging to the authenticated user are visible.
Creating a Custom Action
Actions allow extending the GraphQL schema with custom resolvers. We will create an Action that calls an external microservice for content validation.
Action Declaration
type Mutation {
validateContent(content: String!): ValidationResult!
}
type ValidationResult {
isValid: Boolean!
errors: [String!]!
}This declaration extends the GraphQL schema. The ValidationResult type will be resolved by an external handler.
TypeScript Action Handler
import { Request, Response } from 'express';
export default async (req: Request, res: Response) => {
const { content } = req.body.input;
const isValid = content.length > 10 && !content.includes('spam');
res.json({
isValid,
errors: isValid ? [] : ['Contenu trop court ou spam détecté']
});
};The Express handler validates the content and returns the result. Deploy it on a serverless platform and reference the URL in Hasura.
Event Trigger Configuration
-
name: notify_on_article_publish
table:
schema: public
name: articles
webhook: https://your-webhook.example.com/notify
insert:
columns: "*"
update:
columns: ["published"]
retry_conf:
num_retries: 3
interval_sec: 30This Event Trigger sends a notification on every article publication. The configuration includes retries to ensure reliability in production.
Best Practices
- Always use managed secrets and never expose the admin secret
- Version all metadata in Git with migrations
- Limit exposed columns in each role
- Monitor queries via logs and Prometheus
- Test permissions using the impersonate role in the console
Common Errors to Avoid
- Forgetting to configure CORS on Action handlers
- Using permissive filters without user-id validation
- Ignoring rate-limiting limits on webhooks
- Failing to enable TLS for PostgreSQL connections in production
Going Further
Deepen these concepts with our Hasura Enterprise training. Also explore modules on performance and advanced observability.