Hasura Cheat Sheet
Overview
Hasura is a GraphQL engine that connects to your databases and microservices and instantly provides a production-ready GraphQL and REST API. It supports PostgreSQL, MySQL, SQL Server, BigQuery, and other data sources. Hasura auto-generates queries, mutations, and subscriptions based on your database schema, eliminating the need to write resolver code.
Hasura includes a role-based authorization system, event triggers for async business logic, scheduled triggers for cron jobs, remote schemas for federating other GraphQL services, and Actions for wrapping REST endpoints as GraphQL. It can be self-hosted via Docker or used as a managed cloud service.
Installation
Docker (Self-Hosted)
# Create a docker-compose.yml
cat > docker-compose.yml << 'EOF'
version: "3.6"
services:
postgres:
image: postgres:16
restart: always
volumes:
- db_data:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: postgrespassword
hasura:
image: hasura/graphql-engine:v2.42.0
ports:
- "8080:8080"
restart: always
depends_on:
- postgres
environment:
HASURA_GRAPHQL_METADATA_DATABASE_URL: postgres://postgres:postgrespassword@postgres:5432/postgres
HASURA_GRAPHQL_DATABASE_URL: postgres://postgres:postgrespassword@postgres:5432/postgres
HASURA_GRAPHQL_ENABLE_CONSOLE: "true"
HASURA_GRAPHQL_DEV_MODE: "true"
HASURA_GRAPHQL_ADMIN_SECRET: myadminsecret
volumes:
db_data:
EOF
# Start Hasura
docker compose up -d
# Open console at http://localhost:8080/console
Hasura CLI
# Install the CLI
curl -L https://github.com/hasura/graphql-engine/raw/stable/cli/get.sh | bash
# Or via npm
npm install -g hasura-cli
# Verify installation
hasura version
# Initialize a project
hasura init my-project --endpoint http://localhost:8080 --admin-secret myadminsecret
cd my-project
Core Commands
CLI Commands
| Command | Description |
|---|---|
hasura init | Initialize a new Hasura project |
hasura console | Open the web console with migration tracking |
hasura migrate create | Create a new migration |
hasura migrate apply | Apply pending migrations |
hasura migrate status | Show migration status |
hasura metadata apply | Apply metadata to the server |
hasura metadata export | Export metadata from the server |
hasura seed create | Create a new seed file |
hasura seed apply | Apply seed data |
hasura deploy | Apply migrations and metadata together |
Migration Workflow
# Start console with migration tracking
hasura console --admin-secret myadminsecret
# Create a migration manually
hasura migrate create create_users_table --up-sql \
"CREATE TABLE users (id serial PRIMARY KEY, name text, email text UNIQUE);" \
--down-sql "DROP TABLE users;"
# Apply migrations
hasura migrate apply --admin-secret myadminsecret
# Check status
hasura migrate status --admin-secret myadminsecret
# Rollback last migration
hasura migrate apply --down 1 --admin-secret myadminsecret
# Squash migrations
hasura migrate squash --from 1234567890123 --name merged_migrations
GraphQL Operations
Queries
# Simple query
query {
users {
id
name
email
}
}
# Query with filtering
query {
users(where: { email: { _like: "%@example.com" } }) {
id
name
}
}
# Query with pagination and sorting
query {
users(limit: 10, offset: 20, order_by: { created_at: desc }) {
id
name
created_at
}
}
# Query with relationships
query {
users {
id
name
posts(order_by: { created_at: desc }, limit: 5) {
title
content
}
}
}
# Aggregations
query {
users_aggregate {
aggregate {
count
max { created_at }
}
}
}
Mutations
# Insert
mutation {
insert_users_one(object: { name: "Alice", email: "alice@example.com" }) {
id
name
}
}
# Bulk insert
mutation {
insert_users(objects: [
{ name: "Bob", email: "bob@example.com" },
{ name: "Charlie", email: "charlie@example.com" }
]) {
affected_rows
returning { id name }
}
}
# Update
mutation {
update_users(where: { id: { _eq: 1 } }, _set: { name: "Alice Updated" }) {
affected_rows
}
}
# Delete
mutation {
delete_users(where: { email: { _eq: "old@example.com" } }) {
affected_rows
}
}
# Upsert
mutation {
insert_users_one(
object: { name: "Alice", email: "alice@example.com" }
on_conflict: { constraint: users_email_key, update_columns: [name] }
) {
id
}
}
Subscriptions
# Real-time subscription
subscription {
messages(order_by: { created_at: desc }, limit: 10) {
id
content
user { name }
created_at
}
}
Configuration
Environment Variables
# Core settings
HASURA_GRAPHQL_DATABASE_URL=postgres://user:pass@host:5432/db
HASURA_GRAPHQL_ADMIN_SECRET=your-admin-secret
HASURA_GRAPHQL_ENABLE_CONSOLE=true
HASURA_GRAPHQL_DEV_MODE=true
# Authentication
HASURA_GRAPHQL_JWT_SECRET='{"type":"RS256","jwk_url":"https://auth.example.com/.well-known/jwks.json"}'
HASURA_GRAPHQL_UNAUTHORIZED_ROLE=anonymous
# Performance
HASURA_GRAPHQL_CONNECTIONS_PER_READ_REPLICA=50
HASURA_GRAPHQL_LIVE_QUERIES_MULTIPLEXED_REFETCH_INTERVAL=1000
HASURA_GRAPHQL_STRINGIFY_NUMERIC_TYPES=true
# Logging
HASURA_GRAPHQL_LOG_LEVEL=info
HASURA_GRAPHQL_ENABLED_LOG_TYPES=startup,http-log,webhook-log,websocket-log,query-log
Permissions (Role-Based Access)
# metadata/databases/default/tables/public_users.yaml
- table:
schema: public
name: users
select_permissions:
- role: user
permission:
columns: [id, name, email, avatar_url]
filter:
id: { _eq: X-Hasura-User-Id }
insert_permissions:
- role: user
permission:
columns: [name, avatar_url]
set:
id: X-Hasura-User-Id
check:
id: { _eq: X-Hasura-User-Id }
Advanced Usage
Event Triggers
# Create an event trigger via CLI metadata
# metadata/databases/default/tables/public_orders.yaml
- table:
schema: public
name: orders
event_triggers:
- name: order_created
definition:
enable_manual: false
insert:
columns: "*"
retry_conf:
num_retries: 3
interval_sec: 10
timeout_sec: 60
webhook: https://api.example.com/webhooks/order-created
headers:
- name: x-webhook-secret
value_from_env: WEBHOOK_SECRET
Actions (Custom Business Logic)
# Define an Action
type Mutation {
createUser(name: String!, email: String!): CreateUserOutput
}
type CreateUserOutput {
id: Int!
name: String!
email: String!
}
# Handler endpoint receives:
# POST https://your-api.com/create-user
# { "action": { "name": "createUser" }, "input": { "name": "...", "email": "..." } }
Remote Schemas
# Add a remote GraphQL schema via metadata
hasura metadata apply
# Or add via console: Remote Schemas > Add
Troubleshooting
| Issue | Solution |
|---|---|
| Console not loading | Check HASURA_GRAPHQL_ENABLE_CONSOLE is true; verify port mapping |
| Migration conflicts | Use hasura migrate squash to consolidate; check schema_migrations table |
| Permission denied errors | Verify role permissions in metadata; check JWT claims include correct role |
| Slow queries | Enable query analysis in console; add database indexes for filtered columns |
| Subscription disconnects | Check WebSocket connection limits; increase LIVE_QUERIES_MULTIPLEXED_REFETCH_INTERVAL |
| Metadata out of sync | Run hasura metadata reload or hasura metadata apply |
| Docker OOM | Increase Docker memory limits; reduce connection pool size |
| JWT validation failing | Verify HASURA_GRAPHQL_JWT_SECRET format; check token expiry and claims |