PostgreSQL ist die erste Wahl wenn relationale Daten, JSON-Dokumente, Volltext-Suche und Vektor-Suche in einer Datenbank zusammenkommen sollen. Robust, erweiterbar, kostenlos – und auf jedem Server in Minuten deployt.
Zuletzt aktualisiert:
SQLpgvectorJSONBDockerBackups
PostgreSQL für Automatisierungen und KI-Projekte
Warum PostgreSQL statt SQLite oder MySQL? Drei überzeugende Gründe für moderne Projekte:
JSONB: JSON-Dokumente als natives Typ speichern und indizieren – relationale und dokumentenbasierte Daten in einer Datenbank. Für n8n-Workflow-Daten ideal.
pgvector: Extension für Vektor-Suche direkt in PostgreSQL – kein separater Vektordatenbank-Service nötig. Für RAG-Systeme und Embeddings der pragmatischste Ansatz wenn schon PostgreSQL läuft.
Full-Text-Search:tsvector und tsquery – deutsche Stemming-Unterstützung eingebaut. Für Suche in eigenen Inhalten ohne Elasticsearch.
-- pgvector: Ähnlichkeitssuche in PostgreSQL
CREATE EXTENSION vector;
CREATE TABLE dokumente (
id SERIAL PRIMARY KEY,
inhalt TEXT,
embedding vector(768)
);
-- Nearest Neighbor Search
SELECT inhalt FROM dokumente
ORDER BY embedding <-> '[0.1, 0.2, ...]'
LIMIT 5;
PostgreSQL mit Docker betreiben
PostgreSQL als Docker Compose-Service ist der Standard für selbst gehostete Setups:
Persistenz: Volume für /var/lib/postgresql/data – ohne Volume gehen Daten beim Container-Neustart verloren
Connection Pooling: PgBouncer als Middleware für Anwendungen die viele kurze Verbindungen öffnen – reduziert PostgreSQL-Last massiv
Backups:pg_dump -Fc datenbankname > backup.dump für konsistente Backups. Empfehlenswert: automatisiert per Cron und mit einer Kopie außer Haus, etwa bei S3 oder Backblaze.
Versionen: Postgres 16 ist aktuell empfohlen. Image: postgres:16-alpine für kleinere Container-Größe
n8n, Gitea, Nextcloud und viele andere Services unterstützen PostgreSQL als Backend – eine Instanz für mehrere Services (separate Datenbanken, separate Nutzer).
Performance und Monitoring
PostgreSQL läuft gut mit Standardkonfiguration – aber ein paar Anpassungen helfen:
shared_buffers: 25% des verfügbaren RAMs. Standard sind 128 MB – auf einem 4-GB-Server sollte es 1 GB sein. Das gilt für eine zentrale Datenbank mit Last. Kleine Dienst-Datenbanken laufen bei mir mit den 128 MB problemlos.
EXPLAIN ANALYZE: Für langsame Queries – zeigt den Execution Plan und wo Zeit verloren geht. pg_stat_statements Extension zeigt die teuersten Queries.
Indizes: Fehlendes Index ist die häufigste Performance-Ursache. CREATE INDEX CONCURRENTLY fügt Indizes ohne Table Lock hinzu.
Monitoring:postgres_exporter für Prometheus-Metriken, Grafana-Dashboard für Visualisierung
Eine Postgres-Instanz pro Dienst: So läuft es bei mir
Ich betreibe keine große zentrale PostgreSQL-Instanz. Jeder Dienst, der Postgres braucht, bekommt einen eigenen Container mit postgres:16-alpine (derzeit 16.14 und 16.15). Das hält Updates und Wiederherstellungen getrennt: Wenn ich einen Dienst neu aufsetze, betrifft das keinen anderen.
Alle vier laufen mit den Standardwerten shared_buffers = 128MB und max_connections = 100. Bei diesen Größen reicht das. So sieht das Grundmuster im Docker-Setup aus:
# docker-compose.yml (Ausschnitt)
db:
image: postgres:16-alpine
environment:
POSTGRES_DB: app
POSTGRES_USER: app
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- ./pgdata:/var/lib/postgresql/data
# kein ports: – nur im internen Docker-Netz erreichbar
Daneben gibt es eine PostgreSQL-14-Instanz direkt auf dem Host, mit rund 13 GB Datenverzeichnis. Sie trägt pgvector für eine RAG-Suche über ein großes Nachrichtenarchiv. Die Embeddings liegen dort direkt in Postgres, ohne separate Vektordatenbank.
-- Größe jeder Datenbank prüfen
SELECT datname, pg_size_pretty(pg_database_size(datname))
FROM pg_database ORDER BY pg_database_size(datname) DESC;
Praxiswerte aus der Werkstatt (Stand: Oktober 2026)
Postgres-Container im Einsatz: 4, alle postgres:16-alpine
Host-Instanz mit pgvector: PostgreSQL 14, rund 13 GB
Parallel im Einsatz: SQLite für eine zweite n8n-Instanz und Paperless, MariaDB 11.8 für ältere PHP-Anwendungen
Wann Postgres, wann SQLite, und eine Lehre aus MariaDB
Nicht jeder Dienst bekommt bei mir Postgres. Eine zweite n8n-Instanz und Paperless laufen bewusst mit SQLite. Für einen Dienst mit einem schreibenden Prozess ist eine Datei einfacher als ein weiterer Container.
Die lehrreichste Panne kam aus der MariaDB-Ecke. In MariaDB 11.8 ist STRICT_TRANS_TABLES Standard. Ältere PHP-Anwendungen, die leere Strings in Zahlenspalten schrieben, liefen danach in Fatal Errors. Ich habe das je Anwendung im Code behoben, statt den Strict-Modus global abzuschalten. Global abschalten hätte die Fehler nur wieder unsichtbar gemacht.
-- MariaDB strict / PostgreSQL immer
INSERT INTO rechnung (betrag) VALUES ('');
-- PostgreSQL: ERROR: invalid input syntax for type numeric: ""
Für Postgres heißt das: Es ist von Haus aus so streng. Wer eine alte Anwendung von MySQL oder MariaDB umzieht, sollte mit genau diesen Fehlern rechnen und sie vorher mit Testdaten suchen. Wenn du so etwas nicht selbst betreiben willst, findest du das Angebot unter Hosting.
Häufige Fragen zu PostgreSQL
SQLite für: Einzel-Nutzer-Apps, Prototypen, wenn die App die einzige ist die auf die Daten zugreift. PostgreSQL für: alles was mehr als einen gleichzeitigen Schreiber hat, wenn pgvector oder JSONB gebraucht wird, oder wenn die App produktiv genutzt wird. Wechsel später ist aufwändig – im Zweifel PostgreSQL.
Direkt im Docker Container: `docker exec -it postgres psql -U username datenbankname`. Von außen: `psql "postgresql://user:pass@host:5432/db"`. Grafisches Tool: DBeaver (kostenlos, alle Plattformen) oder pgAdmin 4 als Docker Container.
Nie Port 5432 direkt ins Internet öffnen. Separate DB-User mit minimalen Rechten pro Anwendung (nur SELECT/INSERT/UPDATE, kein DROP). Starke Passwörter, in `.env`-Datei gespeichert. Backups verschlüsseln bevor sie das Haus verlassen.
Migrations-Tool nutzen: Alembic für Python/SQLAlchemy, Flyway oder Liquibase für Java, Prisma Migrate für Node. Nie Schema direkt in Produktion ändern ohne Migration. Immer Backup vor Migration. Rollback-Migration vorbereiten bevor die Forward-Migration ausgeführt wird.
Bei kleinen Dienst-Datenbanken nutze ich je Dienst einen eigenen Container. Die Größen liegen bei mir zwischen 16 und 785 MB, der Mehrbedarf an RAM ist gering, und Updates lassen sich einzeln fahren. Eine gemeinsame Instanz lohnt sich eher, wenn du Monitoring und Backups zentral bündeln willst.