Hasura
Hasura is an open-source engine that connects to your databases (PostgreSQL, MS SQL, etc.) and instantly gives you a production-ready GraphQL API. It simplifies data access, real-time subscriptions, and authorization management, making it ideal for rapidly developing data-driven applications.
You are an expert in Hasura, proficient in leveraging its real-time GraphQL APIs, robust authorization system, and eventing capabilities to build scalable, data-driven web applications. You know how to connect it to various databases, manage schema migrations, and integrate it seamlessly with frontend frameworks using GraphQL clients. ## Key Points * **Batch Mutations:** For operations involving multiple inserts or updates, use `insert_many` or `update_many` mutations where applicable to reduce network overhead and improve efficiency. ## Quick Example ```bash # Create a docker-compose.yaml file touch docker-compose.yaml ``` ```bash # Start Hasura and PostgreSQL docker-compose up -d ```
skilldb get baas-skills/HasuraFull skill: 316 linesYou are an expert in Hasura, proficient in leveraging its real-time GraphQL APIs, robust authorization system, and eventing capabilities to build scalable, data-driven web applications. You know how to connect it to various databases, manage schema migrations, and integrate it seamlessly with frontend frameworks using GraphQL clients.
Core Philosophy
Hasura's core philosophy is to provide an instant, high-performance GraphQL API over your existing databases, eliminating much of the boilerplate associated with building a traditional backend. It focuses on declarative configuration for data access, real-time capabilities, and security, allowing developers to focus on application logic rather than API plumbing. Hasura takes your database schema and automatically generates a comprehensive GraphQL API, complete with querying, mutating, and real-time subscription capabilities.
You choose Hasura when you need to rapidly expose your database data via a GraphQL API, especially when real-time updates are critical or when you're orchestrating data from multiple services. It excels in scenarios where you have an existing database, want to build highly interactive applications, or need a powerful authorization layer without writing extensive custom backend code. It acts as a powerful data access layer, allowing you to centralize data interactions and enforce security policies close to the data source.
Setup
Setting up Hasura typically involves deploying the Hasura Engine and connecting it to your database. For client-side integration, you'll use a GraphQL client like Apollo Client or Relay.
Deploying Hasura Engine (Docker)
For local development or self-hosting, Docker is the most common way to run Hasura.
# Create a docker-compose.yaml file
touch docker-compose.yaml
# docker-compose.yaml
version: '3.6'
services:
postgres:
image: postgres:15
restart: always
volumes:
- db_data:/var/lib/postgresql/data
env_file:
- .env
hasura:
image: hasura/graphql-engine:v2.36.0 # Use a specific stable version
ports:
- "8080:8080"
restart: always
depends_on:
- postgres
env_file:
- .env
volumes:
db_data:
# .env file for database and Hasura configuration
# .env
POSTGRES_DB=mydatabase
POSTGRES_USER=myuser
POSTGRES_PASSWORD=mypassword
HASURA_GRAPHQL_DATABASE_URL=postgres://myuser:mypassword@postgres:5432/mydatabase
HASURA_GRAPHQL_ENABLE_CONSOLE=true
HASURA_GRAPHQL_ADMIN_SECRET=myadminsecretkey # IMPORTANT: Change in production
# Start Hasura and PostgreSQL
docker-compose up -d
Access the Hasura Console at http://localhost:8080.
Client-Side Setup (React with Apollo Client)
npm install @apollo/client graphql
// src/apollo-client.ts
import { ApolloClient, InMemoryCache, HttpLink } from '@apollo/client';
import { setContext } from '@apollo/client/link/context';
const httpLink = new HttpLink({
uri: 'http://localhost:8080/v1/graphql', // Your Hasura GraphQL endpoint
});
const authLink = setContext((_, { headers }) => {
// Get the authentication token from local storage if it exists
const token = localStorage.getItem('jwtToken'); // Or from an auth context
// Return the headers to the context so httpLink can read them
return {
headers: {
...headers,
authorization: token ? `Bearer ${token}` : "",
}
}
});
export const client = new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache(),
});
// src/main.tsx or src/App.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import { ApolloProvider } from '@apollo/client';
import { client } from './apollo-client';
import App from './App';
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<ApolloProvider client={client}>
<App />
</ApolloProvider>
</React.StrictMode>,
);
Key Techniques
1. Querying Data
You query data using standard GraphQL syntax, leveraging Hasura's auto-generated fields and relationships.
// src/App.tsx
import { gql, useQuery } from '@apollo/client';
const GET_TODOS = gql`
query GetTodos {
todos(order_by: {id: asc}) {
id
title
is_completed
}
}
`;
interface Todo {
id: number;
title: string;
is_completed: boolean;
}
interface GetTodosData {
todos: Todo[];
}
function TodosList() {
const { loading, error, data } = useQuery<GetTodosData>(GET_TODOS);
if (loading) return <p>Loading todos...</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<div>
<h2>My Todos</h2>
<ul>
{data?.todos.map(todo => (
<li key={todo.id}>
{todo.title} - {todo.is_completed ? 'Done' : 'Pending'}
</li>
))}
</ul>
</div>
);
}
export default TodosList;
2. Mutating Data (Create, Update, Delete)
Hasura provides mutations for inserting, updating, and deleting data, following GraphQL mutation patterns.
// src/components/AddTodoForm.tsx
import React, { useState } from 'react';
import { gql, useMutation } from '@apollo/client';
const ADD_TODO = gql`
mutation AddTodo($title: String!) {
insert_todos_one(object: {title: $title}) {
id
title
is_completed
}
}
`;
function AddTodoForm() {
const [title, setTitle] = useState('');
const [addTodo, { loading, error }] = useMutation(ADD_TODO, {
refetchQueries: ['GetTodos'], // Refetch the GetTodos query after adding
});
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (!title.trim()) return;
addTodo({ variables: { title } });
setTitle('');
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={title}
onChange={(e) => setTitle(e.target.value)}
placeholder="New todo title"
/>
<button type="submit" disabled={loading}>
{loading ? 'Adding...' : 'Add Todo'}
</button>
{error && <p>Error adding todo: {error.message}</p>}
</form>
);
}
export default AddTodoForm;
3. Real-time Subscriptions
You use subscriptions to get real-time updates for data changes. Hasura leverages WebSockets for this.
// src/components/LiveTodos.tsx
import { gql, useSubscription } from '@apollo/client';
const LIVE_TODOS = gql`
subscription LiveTodos {
todos(where: {is_completed: {_eq: false}}, order_by: {id: asc}) {
id
title
is_completed
}
}
`;
interface Todo {
id: number;
title: string;
is_completed: boolean;
}
interface LiveTodosData {
todos: Todo[];
}
function LiveTodos() {
const { loading, error, data } = useSubscription<LiveTodosData>(LIVE_TODOS);
if (loading) return <p>Loading live todos...</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<div>
<h3>Live Pending Todos</h3>
<ul>
{data?.todos.map(todo => (
<li key={todo.id}>
{todo.title}
</li>
))}
</ul>
</div>
);
}
export default LiveTodos;
4. Authorization with JWT
Hasura integrates with JWTs to provide powerful row-level and column-level authorization. You send a JWT in the Authorization header, and Hasura uses its claims (e.g., x-hasura-user-id, x-hasura-role) to enforce access rules.
// Example of how a JWT payload might look (after being signed by your auth service)
{
"https://hasura.io/jwt/claims": {
"x-hasura-allowed-roles": ["user", "admin"],
"x-hasura-default-role": "user",
"x-hasura-user-id": "123",
"x-hasura-org-id": "456"
},
"sub": "auth0|12345",
"iat": 1516239022,
"exp": 1516242622
}
When making a request with Apollo Client, the authLink from the setup section automatically attaches this token. Hasura then interprets the x-hasura-* claims to apply the configured permissions. For instance, you can define a rule like "a user can only see todos where user_id matches x-hasura-user-id".
Best Practices
- Use Migrations for Schema Changes: Always manage your database schema and Hasura metadata changes using the Hasura CLI's migration system. This ensures version control, consistency across environments, and proper rollback capabilities.
- Implement Robust Authorization: Leverage Hasura's powerful Role-Based Access Control (RBAC) and Row-Level Security (RLS) extensively. Define granular permissions for every role and table to prevent unauthorized data access.
- Optimize Queries with Indices: While Hasura provides the API, database performance is still key. Ensure your database tables have appropriate indices for fields frequently used in
whereclauses,order_by, andjoinconditions. - Batch Mutations: For operations involving multiple inserts or updates, use
insert_manyorupdate_manymutations where applicable to reduce network overhead and improve efficiency. - Monitor Performance: Utilize Hasura's built-in metrics and integrate with external monitoring tools to track API performance, slow queries, and error rates. Optimize your database or Hasura configuration based on these insights.
- Secure Environment Variables: Never hardcode sensitive information like
HASURA_GRAPHQL_ADMIN_SECRETor database credentials. Use environment variables, and ensure they are managed securely in production. - Generate Types for Client-Side: Use GraphQL code generation tools (e.g., GraphQL Code Generator) to create TypeScript types from your Hasura schema and queries. This provides type safety and a better developer experience.
Anti-Patterns
Ignoring Authorization. Failing to define comprehensive Row-Level Security and permissions means your data is exposed. Always assume malicious intent and define strict access rules for every role, table, and column.
Manual Schema Management. Directly modifying your database schema or Hasura metadata via the console in production environments leads to inconsistencies and difficult debugging. Always use the Hasura CLI for migrations and metadata application.
Over-fetching or Under-fetching Data. Sending overly broad queries (over-fetching) or making many small queries instead of one optimized query (under-fetching) leads to inefficient network usage. Leverage GraphQL's flexibility to fetch exactly what you need in a single request.
Client-Side Data Joins. Attempting to join data from multiple tables by fetching them separately on the client. Instead, define relationships in Hasura and use nested GraphQL queries to fetch related data efficiently in a single trip.
Using Admin Secret in Client-Side Code. Exposing your HASURA_GRAPHQL_ADMIN_SECRET in any client-side application is a critical security vulnerability, granting full unrestricted access to your Hasura instance. The admin secret should only be used by trusted backend services or for initial setup, never in the browser.
Install this skill directly: skilldb add baas-skills
Related Skills
Appwrite
Appwrite self-hosted BaaS with database, auth, storage, and serverless functions
AWS Amplify
AWS Amplify BaaS with AppSync GraphQL, Cognito auth, S3 storage, and Lambda functions
Backendless
Backendless BaaS with real-time database, user authentication, Cloud Code,
Clerk Auth
Clerk authentication service with pre-built UI components, session management, and multi-framework support
Convex
Convex real-time backend with reactive queries, mutations, and serverless functions
Encore
Encore is a backend development platform that automatically provisions, configures, and manages cloud infrastructure based on your Go code. It simplifies building and deploying cloud-native applications by allowing you to focus purely on business logic.