über PostgreSQL: wann sich der Ansatz lohnt
Hasura verwandelt eine bestehende PostgreSQL-Datenbank in Sekunden in eine vollständige GraphQL-API, inklusive Filtern, Sortierung, Pagination und Beziehungen, ganz ohne einen einzigen Resolver zu schreiben. Der Ansatz eignet sich hervorragend für bestimmte Szenarien und ist für andere komplett ungeeignet. Dieser Artikel zeigt konkret, wo die Grenze verläuft.
Inhaltsverzeichnis
- 1. Was ist Hasura und wie generiert es GraphQL aus PostgreSQL
- 2. Setup: Docker, Metadata und erste Tabelle
- 3. Permissions: Row-Level-Security im Berechtigungssystem
- 4. Relationships: Object- und Array-Beziehungen modellieren
- 5. Custom-Logik: Actions und Event-Triggers
- 6. Remote Schemas und Remote Joins
- 7. Performance: Query-Caching und Connection-Pooling
- 8. Wann Hasura NICHT passt
- 9. Hasura vs. handgeschriebenes GraphQL
- 10. Zusammenfassung
- 11. FAQ
1. Was ist Hasura und wie generiert es GraphQL aus PostgreSQL
Hasura ist eine GraphQL-Engine, die sich mit einer bestehenden PostgreSQL-Datenbank verbindet, das Datenbankschema per Introspection ausliest und daraus automatisch ein vollständiges GraphQL-Schema mit Queries, Mutations und Subscriptions für jede Tabelle generiert. Anders als bei graphql-php, Lighthouse oder NestJS GraphQL schreibt bei Hasura niemand Resolver-Code, das Query-Verhalten wird direkt in performantes SQL übersetzt, mit optimierten Joins für verschachtelte Beziehungsabfragen.
Der zentrale Denkfehler beim ersten Kontakt mit Hasura ist, es als reines Entwicklungswerkzeug für Prototypen zu betrachten. Tatsächlich betreiben zahlreiche Unternehmen Hasura produktiv als primäre Daten-API, weil die generierten Queries in der Regel effizienter sind als naiv geschriebene Resolver-Ketten, und weil die eingebaute Permission-Engine echte Row-Level-Security auf Datenbankebene durchsetzt, nicht nur auf Anwendungsebene. Für Domänen, deren GraphQL-Struktur eng am relationalen Schema hängt, ist Hasura also durchaus produktionstauglich, nicht nur ein Entwicklungs-Hilfsmittel.
2. Setup: Docker, Metadata und erste Tabelle
Der schnellste Einstieg in Hasura läuft über Docker Compose, das den Hasura-GraphQL-Engine-Container zusammen mit einer PostgreSQL-Instanz startet. Nach dem Start verbindet sich Hasura über eine Connection-String-Konfiguration mit der Datenbank und zeigt im integrierten Console-Interface alle vorhandenen Tabellen an, jede einzelne mit einem Klick als GraphQL-Typ aktivierbar. Diese Konfiguration, welche Tabellen, Views und Funktionen exponiert werden, landet in versionierbaren YAML-Metadata-Dateien, die sich wie normaler Code in Git verwalten lassen.
Wichtig für produktive Setups: Die Metadata-Dateien sollten nie ausschließlich über die Web-Console verändert werden, sondern über hasura metadata export und hasura metadata apply als Teil eines CI/CD-Workflows, damit Änderungen an Permissions, Relationships und Actions nachvollziehbar reviewt werden können, statt sich unversioniert in der laufenden Instanz anzusammeln.
# docker-compose.yaml — Hasura GraphQL Engine with PostgreSQL
version: "3.6"
services:
postgres:
image: postgres:16
environment:
POSTGRES_PASSWORD: postgrespassword
volumes:
- db_data:/var/lib/postgresql/data
graphql-engine:
image: hasura/graphql-engine:v2.40.0
ports:
- "8080:8080"
environment:
HASURA_GRAPHQL_DATABASE_URL: postgres://postgres:postgrespassword@postgres:5432/postgres
HASURA_GRAPHQL_ENABLE_CONSOLE: "true"
HASURA_GRAPHQL_ADMIN_SECRET: changeme
depends_on:
- postgres
volumes:
db_data:
-- products table — Hasura tracks this and exposes it as a GraphQL type instantly
CREATE TABLE products (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
sku TEXT UNIQUE NOT NULL,
name TEXT NOT NULL,
price NUMERIC(10, 2) NOT NULL,
category_id UUID REFERENCES categories(id),
created_at TIMESTAMPTZ DEFAULT now()
);
3. Permissions: Row-Level-Security im Berechtigungssystem
Das Hasura-Berechtigungssystem definiert pro Tabelle und Rolle separate Regeln für Select, Insert, Update und Delete, jede als deklarativer Filterausdruck ähnlich einer SQL-WHERE-Klausel. Eine Regel wie {"customer_id": {"_eq": "X-Hasura-User-Id"}} sorgt dafür, dass ein authentifizierter Kunde ausschließlich seine eigenen Bestellungen sehen kann, wobei X-Hasura-User-Id ein Session-Variable ist, die von der Authentifizierungsschicht, meist über JWT-Claims, gesetzt wird.
Der entscheidende Vorteil dieses Modells gegenüber Autorisierungslogik in Resolver-Code: Die Row-Level-Permission wird direkt in die generierte SQL-Query als zusätzliche WHERE-Bedingung eingebettet, es gibt also keinen Weg, sie versehentlich zu umgehen, weil sie nicht als separater, potenziell vergessener Prüfschritt existiert, sondern strukturell Teil jeder einzelnen Abfrage ist. Für Spalten-Ebene bietet Hasura zusätzlich Column-Permissions, mit denen sich etwa ein internal_notes-Feld nur für die Rolle admin sichtbar machen lässt.
// Hasura metadata — row-level permission for role "customer" on table "orders"
{
"table": { "schema": "public", "name": "orders" },
"select_permissions": [
{
"role": "customer",
"permission": {
"columns": ["id", "status", "total", "created_at"],
"filter": {
"customer_id": { "_eq": "X-Hasura-User-Id" }
},
"limit": 100
}
}
]
}
4. Relationships: Object- und Array-Beziehungen modellieren
Beziehungen zwischen Tabellen werden in Hasura als Object-Relationship für Many-to-One und Array-Relationship für One-to-Many oder Many-to-Many konfiguriert, jeweils auf Basis der bestehenden Foreign-Key-Constraints in PostgreSQL. Existiert bereits ein Foreign Key, erkennt Hasura die Beziehung automatisch und schlägt sie zur Aktivierung vor, ansonsten lässt sich die Beziehung auch manuell über beliebige Spaltenkombinationen definieren, etwa für Legacy-Schemas ohne saubere Foreign-Key-Constraints.
Verschachtelte GraphQL-Queries über diese Relationships übersetzt Hasura automatisch in effiziente SQL-Joins, ganz ohne das klassische N+1-Problem, das bei handgeschriebenen Resolvern ohne DataLoader typisch ist. Eine Query nach 50 Produkten mit jeweils zugehöriger Kategorie erzeugt bei Hasura eine einzige SQL-Abfrage mit JOIN, nicht 51 separate Abfragen, ein struktureller Performance-Vorteil gegenüber naiv implementierten Resolver-basierten APIs.
# Nested query resolved by Hasura as a single SQL JOIN, no manual DataLoader needed
query ProductsWithCategory {
products(where: { price: { _gt: 20 } }, order_by: { created_at: desc }) {
id
sku
name
price
category {
id
name
}
}
}
5. Custom-Logik: Actions und Event-Triggers
Für Geschäftslogik, die sich nicht als reine Datenbankabfrage ausdrücken lässt, etwa eine Zahlungsabwicklung über einen externen Payment-Provider, bietet Hasura Actions: benutzerdefinierte GraphQL-Mutations, die im generierten Schema erscheinen, aber intern einen HTTP-Request an einen selbst geschriebenen Webhook-Endpunkt auslösen. Der Actions-Mechanismus erlaubt so, beliebigen eigenen Code, etwa in Node.js oder Go, nahtlos in das GraphQL-Schema einzubinden, ohne den Auto-Generierungsansatz für den Rest der API aufzugeben.
Event-Triggers gehen den umgekehrten Weg: Statt auf einen GraphQL-Request zu reagieren, feuern sie automatisch, sobald sich Daten in einer überwachten Tabelle ändern, etwa nach jedem INSERT in die orders-Tabelle. Der Trigger sendet einen HTTP-Request an einen konfigurierten Endpunkt, ideal für Aufgaben wie das Versenden von Bestätigungs-E-Mails oder das Anstoßen asynchroner Hintergrundverarbeitung, ohne dass die Datenbank selbst Trigger-Logik in PL/pgSQL enthalten müsste.
6. Remote Schemas und Remote Joins
Für Fälle, in denen eine bereits existierende GraphQL-API, etwa ein separater Microservice, mit den Hasura-generierten Daten kombiniert werden soll, bietet Hasura Remote Schemas: Ein fremdes GraphQL-Schema wird als zusätzliche Datenquelle registriert und erscheint im vereinten Hasura-Schema neben den datenbankgenerierten Typen, als würde alles aus einer einzigen API kommen. Das eignet sich hervorragend für die schrittweise Migration bestehender Systeme in Richtung Hasura, ohne alles auf einmal umbauen zu müssen.
Remote Joins gehen noch einen Schritt weiter und erlauben, Felder aus dem Remote Schema direkt mit lokalen Datenbanktypen zu verknüpfen, sodass ein Produkt aus der Datenbank ein Feld inventoryStatus aus einem separaten Inventory-Microservice referenzieren kann, als wäre es eine normale Datenbankspalte. Diese Fähigkeit macht Hasura zu einer echten API-Gateway-Alternative für Teams, die verschiedene Datenquellen unter einem einzigen GraphQL-Endpunkt vereinen möchten.
7. Performance: Query-Caching und Connection-Pooling
Hasura bringt eingebautes Query-Response-Caching mit, das häufig wiederholte Queries anhand ihrer Struktur und Variablen cacht, konfigurierbar über eine @cached-Direktive direkt in der GraphQL-Query. Für Lesezugriffe auf selten wechselnde Daten, etwa eine Produktkategorie-Liste, reduziert das die Datenbanklast erheblich, ohne dass ein separates Caching-Layer wie Redis manuell integriert werden müsste.
Für Connection-Pooling zur Datenbank nutzt Hasura standardmäßig einen internen Pool, dessen Größe sich über HASURA_GRAPHQL_PG_CONNECTIONS konfigurieren lässt. Bei hoher Parallelität empfiehlt sich zusätzlich ein vorgeschalteter externer Pooler wie PgBouncer, weil PostgreSQL selbst mit einer begrenzten Anzahl gleichzeitiger Verbindungen arbeitet und ein unkontrolliert wachsender Hasura-Pool bei Lastspitzen schnell an diese Grenze stößt.
8. Wann Hasura NICHT passt
So mächtig der Auto-Generierungsansatz von Hasura ist, für bestimmte Szenarien ist er strukturell ungeeignet. Domänen mit komplexer, mehrstufiger Geschäftslogik, etwa ein Bestellprozess mit Rabattregeln, Lagerbestandsprüfung und mehreren Validierungsschritten, lassen sich nicht sinnvoll als reine Datenbankoperation ausdrücken. Zwar lässt sich das über Actions lösen, aber dann verlagert sich der Großteil der eigentlichen Logik ohnehin wieder in selbst geschriebenen Code, und der Auto-Generierungsvorteil von Hasura schrumpft entsprechend.
Ebenfalls ungeeignet ist Hasura für GraphQL-Schemas, die bewusst stark von der relationalen Datenbankstruktur abweichen sollen, etwa wenn das API-Design aus fachlichen Gründen anders aussehen soll als das zugrunde liegende Tabellenschema. Und für Teams, die volle Kontrolle über jeden Aspekt der Query-Ausführung brauchen, etwa für sehr spezifisches Custom-Caching pro Feld, ist der deklarative Hasura-Ansatz einschränkender als eine handgeschriebene graphql-php- oder NestJS-Lösung mit vollständig freien Resolvern.
9. Hasura vs. handgeschriebenes GraphQL
Die Entscheidung zwischen Hasura und einer manuell geschriebenen GraphQL-API hängt stark davon ab, wie eng die Domäne an die relationale Datenbankstruktur gekoppelt ist.
| Kriterium | Hasura | Handgeschriebenes GraphQL |
|---|---|---|
| Zeit bis zur ersten funktionierenden API | Minuten | Tage bis Wochen |
| N+1-Vermeidung | Automatisch per SQL-Join | Manuell per DataLoader |
| Komplexe Geschäftslogik | Nur über Actions, mit eigenem Code | Nativ im Resolver |
| Schema-Struktur vs. DB-Struktur | Eng gekoppelt | Frei wählbar |
| Row-Level-Security | Eingebaut, deklarativ | Selbst zu implementieren |
Für datengetriebene Anwendungen mit überwiegend CRUD-artigen Zugriffsmustern und klaren Row-Level-Berechtigungen, etwa interne Admin-Tools, Dashboards oder Backend-for-Frontend-Schichten über einer bestehenden Datenbank, ist Hasura oft die schnellere und wartungsärmere Wahl. Für Domänen mit tiefer, verzweigter Geschäftslogik oder einem API-Design, das bewusst von der Datenbankstruktur abweicht, bleibt eine handgeschriebene Lösung mit graphql-php, Lighthouse oder NestJS die passendere Grundlage.
Mironsoft
GraphQL-, PostgreSQL- und API-Architektur für datenintensive Systeme
Prüfen, ob Hasura zu eurer Datenbank passt?
Wir bewerten eure PostgreSQL-Struktur, richten Hasura mit sauberen Row-Level-Permissions und Relationships ein und zeigen ehrlich, wo Actions oder eine handgeschriebene GraphQL-Lösung die bessere Wahl sind.
Hasura-Setup
Metadata-basierte Konfiguration, versioniert und CI/CD-tauglich einrichten
Permissions & Security
Row- und Column-Level-Permissions passend zu eurem Rollenmodell modellieren
Architektur-Review
Ehrliche Einschätzung, wann Hasura passt und wann nicht
10. Zusammenfassung
Hasura generiert aus einer PostgreSQL-Datenbank eine vollständige, performante GraphQL-API mit Row-Level-Permissions, automatisch erkannten Relationships und eingebauter N+1-Vermeidung durch SQL-Joins, ganz ohne einen einzigen Resolver zu schreiben. Für datengetriebene Anwendungen mit überwiegend CRUD-artigen Zugriffsmustern reduziert das die Entwicklungszeit von Wochen auf Minuten und liefert dabei eine deklarative, in Metadata versionierbare Konfiguration.
Der Auto-Generierungsansatz stößt jedoch an klare Grenzen: komplexe, mehrstufige Geschäftslogik, die sich nicht als Datenbankoperation ausdrücken lässt, und Schemas, die bewusst von der relationalen Struktur abweichen sollen, passen strukturell schlecht zu Hasura. Actions und Remote Schemas mildern diese Einschränkung ab, ersetzen aber nicht vollständig die Flexibilität einer handgeschriebenen graphql-php-, Lighthouse- oder NestJS-Lösung. Die richtige Wahl hängt letztlich davon ab, wie eng die eigene Domäne an das relationale Datenbankschema gekoppelt ist.
Hasura als Instant GraphQL API — Das Wichtigste auf einen Blick
Auto-Generierung
Vollständiges GraphQL-Schema direkt aus PostgreSQL-Introspection, versioniert in Metadata-YAML-Dateien.
Permissions
Row- und Column-Level-Security als Teil jeder generierten SQL-Query, nicht umgehbar wie Resolver-basierte Checks.
Actions & Remote Schemas
Eigener Code und externe APIs lassen sich nahtlos ins generierte Schema integrieren.
Grenzen
Komplexe Geschäftslogik und stark abweichende Schema-Designs passen strukturell schlecht zum Ansatz.