TechnologieProgrammierung

Baserow als gemeinsame Redaktionsdatenbank für Website-Portfolios

netcomputing.de Redaktion26. August 20269 Min. Lesezeit

Zusammenfassung

Wer viele Next.js-Websites betreibt, baut sonst je Projekt ein eigenes Redaktionssystem oder nutzt eine gemeinsame Baserow-Instanz. Deren REST-API liefert Zeilen per Database-Token und Filtern wie filter__field_123__contains, sodass jede Website nur ihre eigenen Daten lädt. Ein Token lässt sich auf einzelne Tabellen beschränken, aber nicht auf einzelne Zeilen, das entscheidet zwischen gemeinsamer Tabelle und eigener Datenbank je Website. Für ein komplexes Einzelprojekt bleibt oft ein Headless-CMS die bessere Wahl.

Systemvoraussetzungen

Wer für ein Portfolio aus zehn, zwanzig oder vierzig eigenständigen Next.js-Websites Inhalte pflegen will, braucht dafür kein eigenes Content-Management-System je Projekt. Baserow, eine quelloffene, selbstgehostete No-Code-Datenbank mit vollständiger REST-API (einer Programmierschnittstelle, über die andere Programme Daten per HTTP lesen und schreiben), übernimmt die Redaktion für alle Websites aus einer gemeinsamen Instanz. Die folgende Tabelle nennt die Komponenten und Versionen, die dieser Aufbau voraussetzt.

KomponenteVersion / Anforderung
Baserow2.3.3 (aktueller Stable-Release, All-in-One-Image baserow/baserow)
Docker Enginemit Compose-Plugin (Befehl docker compose)
PostgreSQLläuft im All-in-One-Image intern mit; für den Produktivbetrieb per DATABASE_URL extern anbindbar
Redisläuft im All-in-One-Image intern mit; für den Produktivbetrieb per REDIS_URL extern anbindbar
Node.jsLTS ab Version 18, für den Next.js-Build und die Fetch-Aufrufe zur Laufzeit
Next.jsApp Router mit fetch-basiertem Data Fetching und ISR, seit Next.js 13 unterstützt
Database-Tokenje Website oder Website-Gruppe erzeugt, mit einzeln schaltbaren Rechten für Erstellen, Lesen, Aktualisieren, Löschen

Systemarchitektur

In einer gemeinsamen Baserow-Instanz pflegt eine Redakteurin alle Inhalte für sämtliche angeschlossenen Websites in einem einzigen Werkzeug. Jede Next.js-Website ruft beim Build oder zur Laufzeit nur die Zeilen ab, die zu ihr gehören, entweder über eine eigene Tabelle oder über einen Filter auf ein gemeinsames Feld. Das folgende Diagramm zeigt beide Wege, über die eine Änderung in Baserow am Ende auf einer ausgelieferten Seite ankommt.

flowchart TD
    A[Redakteurin aendert eine Zeile in Baserow] --> B[Baserow speichert die Aenderung in der internen Postgres-Datenbank]
    B --> C[Baserow loest den Webhook rows.updated aus]
    C --> D[Ein schlanker Webhook-Empfaenger auf der betroffenen Website nimmt das Ereignis an]
    D --> E[Der Empfaenger stoesst eine gezielte On-Demand-Revalidierung der betroffenen Seite an]
    F[Naechster Next-js-Build oder ISR-Intervall startet unabhaengig davon] --> G[Next-js ruft die Baserow-REST-API mit Database-Token und Site-Filter auf]
    G --> H{Antwortstatus der Baserow-API}
    H -->|200 mit Zeilen| I[Next-js rendert die Seite mit den gefilterten Datensaetzen]
    H -->|401 Token ungueltig| J[Build bricht ab und das Monitoring meldet den Fehler]
    H -->|200 mit leerem Ergebnis| K[Seite zeigt einen definierten Leerzustand]

Der schnelle Weg über den Webhook lohnt sich für Inhalte, die sofort erscheinen sollen, ein neuer Artikel oder eine korrigierte Preisangabe zum Beispiel. Baserow schickt dafür bei den Ereignissen rows.created, rows.updated und rows.deleted einen HTTP-Aufruf an eine hinterlegte URL; die älteren Einzelereignisse row.created, row.updated und row.deleted gelten laut Baserows eigener Dokumentation als veraltet und sollen durch die neueren Sammelereignisse ersetzt werden. Der langsamere Weg über den nächsten Next.js-Build oder das nächste ISR-Intervall (Incremental Static Regeneration, das automatische Neuerzeugen einer statischen Seite nach Ablauf einer festgelegten Zeitspanne) reicht für Inhalte, bei denen ein paar Minuten oder Stunden Verzögerung niemanden stören.

Schritt-für-Schritt-Umsetzung

Docker Compose startet die gemeinsame Baserow-Instanz

Der Container läuft einmal für das ganze Portfolio und bringt in der All-in-One-Variante eine interne Postgres-Datenbank und einen internen Redis-Server bereits mit.

services:
  baserow:
    container_name: baserow
    image: baserow/baserow:2.3.3
    environment:
      BASEROW_PUBLIC_URL: "https://redaktion.intern.example.de"
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - baserow_data:/baserow/data
    restart: unless-stopped

volumes:
  baserow_data:

Für den Produktivbetrieb mit mehreren gleichzeitigen Redakteuren empfiehlt Baserows eigene Dokumentation, die interne Postgres-Datenbank und den internen Redis-Server durch extern betriebene Dienste zu ersetzen: DATABASE_URL verbindet die Instanz mit einer eigenen Postgres-Datenbank, REDIS_URL mit einem eigenen Redis-Server. Für einen ersten Testbetrieb bleibt beides optional, für ein produktives Portfolio mit täglichem Redaktionsbetrieb erleichtert es aber das Backup, weil die Datenbank dann unabhängig vom Container gesichert wird.

Ein Database-Token erhält Rechte für genau eine Tabelle oder Datenbank

Ein Database-Token entsteht in den Arbeitsbereich-Einstellungen unter dem Reiter Database-Tokens und lässt sich beim Erzeugen entweder auf den gesamten Arbeitsbereich oder auf einzelne Tabellen einschränken, dazu je Vorgang einzeln auf Erstellen, Lesen, Aktualisieren und Löschen. Ein Token ändert nie die Struktur einer Tabelle, also weder Spalten noch Tabellen selbst; dafür verlangt Baserow ein persönliches JWT-Token aus dem normalen Login. Diese Grenze, ein Token wirkt bis auf die Ebene einzelner Tabellen, aber nicht auf einzelne Zeilen darin, entscheidet direkt über die Wahl zwischen zwei Aufbauten für ein Portfolio.

  • Eine gemeinsame Tabelle mit einem Site-Feld. Alle Websites teilen sich ein Schema, eine neue Spalte steht sofort überall zur Verfügung, und die Pflege eines einzigen Schemas kostet deutlich weniger Aufwand als vierzig gleichartige. Der Nachteil: Ein Token mit Lesezugriff auf diese Tabelle kann grundsätzlich jede Zeile lesen, unabhängig vom Site-Feld. Die Trennung nach Website entsteht dann ausschließlich durch den Filter-Parameter im Next.js-Code, nicht durch eine Berechtigung von Baserow.
  • Eine eigene Datenbank je Website. Ein Token für Website A kann technisch nicht auf die Tabellen von Website B zugreifen, weil beide in getrennten Datenbanken liegen und sich ein Token auf eine davon beschränken lässt. Der Nachteil: Jede neue Website dupliziert das Tabellenschema, und eine Schemaänderung, ein neues Pflichtfeld etwa, muss von Hand in jeder einzelnen Datenbank nachgezogen werden.

Für Inhalte ohne echten Schutzbedarf, öffentliche Blogartikel etwa, überwiegt meist die gemeinsame Tabelle. Sobald eine Website Zugangsdaten, unveröffentlichte Preise oder Kundendaten anderer Websites niemals sehen darf, wiegt die getrennte Datenbank den doppelten Pflegeaufwand auf.

Eine gefilterte Abfrage holt nur die Zeilen einer Website

Baserows REST-API filtert Zeilen über Query-Parameter der Form filter__feld__operator, wobei das Feld über seine numerische Feld-ID statt über den änderbaren Spaltennamen angesprochen wird.

curl -H "Authorization: Token $BASEROW_API_TOKEN" \
  "https://baserow.intern.example.de/api/database/rows/table/523/?filter__field_4821__equal=website-a&size=200"

Der Header Authorization: Token <Wert> ist die von Baserow vorgeschriebene Form für Database-Token, nicht Bearer und nicht JWT; jenes Präfix gilt nur für die persönlichen Zugriffstoken aus dem normalen Login. filter__field_4821__equal=website-a lässt ausschließlich Zeilen durch, deren Feld 4821 den Wert website-a trägt. Bleibt der Parameter size weg, liefert ein Aufruf üblicherweise 100 Zeilen pro Seite. Die Obergrenze pro Seite lässt sich über die Server-Einstellung BASEROW_ROW_PAGE_SIZE_LIMIT konfigurieren, die in einer Standardinstallation bei 200 liegt; ein höherer angeforderter Wert schlägt mit dem Fehler ERROR_PAGE_SIZE_LIMIT fehl. Die Antwort selbst liefert neben den Zeilen im Feld results auch count für die Gesamtzahl der Treffer sowie next und previous mit den URLs der Nachbarseiten, sodass sich mehrere Seiten programmatisch durchlaufen lassen.

Eine Next.js-ISR-Route liest die Zeilen ein und rendert die Seite

Next.js ruft dieselbe gefilterte Abfrage serverseitig auf und übergibt der eingebauten fetch-Funktion eine Revalidierungszeit, nach der die Seite spätestens neu erzeugt wird.

async function getArticlesForSite(site: string) {
  const url = new URL("https://baserow.intern.example.de/api/database/rows/table/523/");
  url.searchParams.set("filter__field_4821__equal", site);
  url.searchParams.set("size", "200");

  const res = await fetch(url, {
    headers: {
      Authorization: `Token ${process.env.BASEROW_API_TOKEN}`,
    },
    next: { revalidate: 3600 },
  });

  if (!res.ok) {
    throw new Error(`Baserow antwortete mit Status ${res.status}`);
  }

  const data = await res.json();
  return data.results;
}

revalidate: 3600 sorgt dafür, dass Next.js die Seite höchstens einmal pro Stunde aus Baserow neu lädt, selbst wenn in der Zwischenzeit kein Webhook eintrifft. Für Seiten, die sofort auf eine Redaktionsänderung reagieren sollen, ruft der Webhook-Empfänger aus dem Architekturdiagramm stattdessen gezielt revalidatePath für die betroffene Seite auf, sobald das Ereignis rows.updated eintrifft.

Häufige Fehlerquellen

  • 401 mit dem Fehlercode ERROR_INVALID_ACCESS_TOKEN. Der Next.js-Build bricht beim Zeilen-Abruf ab, weil das Token abgelaufen, falsch kopiert oder mit dem falschen Präfix gesendet wurde. Fix: ein neues Database-Token erzeugen und den Header exakt als Authorization: Token <Wert> setzen, nicht Bearer und nicht JWT.
  • Eine Website liest Zeilen einer anderen Website mit. Fremde Inhalte tauchen auf einer Seite auf, obwohl das eigene Redaktionsteam sie nie eingetragen hat. Ursache ist fast immer ein vergessener oder falsch gesetzter Filter-Parameter im Next.js-Code, während das verwendete Token Lesezugriff auf die gesamte gemeinsame Tabelle hat. Fix: den Site-Filter serverseitig fest verdrahten statt aus Nutzereingaben zu übernehmen, und bei schützenswerten Inhalten eine eigene Tabelle oder Datenbank je Website verwenden.
  • ERROR_PAGE_SIZE_LIMIT beim Versuch, mehr Zeilen als erlaubt auf einmal zu laden. Fix: den Parameter size innerhalb der über BASEROW_ROW_PAGE_SIZE_LIMIT erlaubten Grenze halten und stattdessen dem Feld next aus der Antwort folgen, um weitere Seiten nachzuladen.
  • Der Webhook-Empfänger antwortet nicht mit Status 200. Eine Seite zeigt trotz frischer Redaktionsänderung noch den alten Stand. Baserow wiederholt die Zustellung eines fehlgeschlagenen Webhook-Aufrufs nur eine begrenzte Anzahl Mal und gibt danach auf. Fix: Der Webhook-Empfänger bestätigt den Empfang sofort mit 200 und verarbeitet das Ereignis erst danach, statt die Antwort auf eine langwierige Revalidierung warten zu lassen.
  • Die Next.js-Seite baut mit veralteten Daten, obwohl in Baserow längst alles korrigiert ist. Ohne Webhook und ohne kurzes Revalidierungsintervall liest eine ISR-Seite ihre Baserow-Zeilen erst beim nächsten planmäßigen Build neu ein. Fix: für redaktionell aktive Tabellen zusätzlich den Webhook einrichten und gezielt revalidatePath aufrufen, statt sich allein auf ein festes Zeitintervall zu verlassen.

Häufig gestellte Fragen

Kann ein Baserow-Database-Token nur eine Website lesen?

Ein Baserow-Database-Token kann nur die Daten einer Website lesen, wenn es beim Erzeugen auf genau die Tabellen oder die Datenbank dieser Website beschränkt wurde. Erlaubt das Token dagegen Lesezugriff auf eine Tabelle, die sich mehrere Websites über ein gemeinsames Site-Feld teilen, kann es technisch jede Zeile dieser Tabelle lesen; die Trennung nach Website entsteht dann ausschließlich über den Filter-Parameter in der Abfrage, nicht über eine Berechtigung von Baserow selbst. Für eine Trennung, die auch bei einem fehlerhaften Filter noch hält, braucht jede Website ihre eigene Tabelle oder Datenbank mit einem eigenen, entsprechend eingeschränkten Token.

Was passiert, wenn eine Next.js-Seite mehr als 200 Zeilen aus Baserow braucht?

Mehr Zeilen als die konfigurierte Obergrenze liefert ein einzelner Aufruf der Baserow-API nicht; ein zu hoch gesetzter Parameter size löst stattdessen den Fehler ERROR_PAGE_SIZE_LIMIT aus. Jede Antwort enthält zusätzlich zu den Zeilen im Feld results ein count-Feld mit der Gesamtzahl der Treffer und ein next-Feld mit der URL zur nächsten Seite, sodass eine Next.js-Route so lange nachlädt, bis next den Wert null trägt. Bei mehreren Tausend Zeilen lohnt sich zusätzlich ein engerer Filter, damit nicht bei jedem Build ohnehin nur ein Bruchteil der geladenen Zeilen tatsächlich verwendet wird.

Lohnt sich Baserow als Redaktionsdatenbank auch für eine einzelne, inhaltlich komplexe Website?

Für eine einzelne, inhaltlich komplexe Website lohnt sich Baserow als alleinige Redaktionsdatenbank in den meisten Fällen nicht. Ein dediziertes Headless-CMS bringt Funktionen mit, die eine tabellenbasierte Datenbank wie Baserow nicht abbildet: verschachtelte, wiederverwendbare Content-Blöcke, ein eingebautes Freigabe- und Versionierungssystem für Redakteure sowie eigene Feldtypen für strukturierten Rich-Text statt reiner Zellenwerte. Der Vorteil einer gemeinsamen Baserow-Instanz zeigt sich erst, sobald mehrere Websites sich dieselbe Infrastruktur, dasselbe Redaktions-Login und einen gemeinsamen Server teilen, statt für jedes einzelne Projekt ein eigenes CMS zu hosten und zu pflegen.

Wie erfährt eine Next.js-Website, dass sich eine Baserow-Zeile geändert hat?

Eine Next.js-Website erfährt von einer geänderten Baserow-Zeile entweder über das nächste ISR-Intervall, in dem die gesetzte Revalidierungszeit ohnehin abläuft, oder sofort über einen Webhook. Baserow löst bei den Ereignissen rows.created, rows.updated und rows.deleted einen HTTP-Aufruf an eine hinterlegte URL aus und schickt die betroffenen Zeilen im JSON-Feld items mit, bei aktualisierten Zeilen zusätzlich den vorherigen Stand im Feld old_items. Antwortet der Empfänger auf der Website nicht mit dem Status 200, wiederholt Baserow die Zustellung nur eine begrenzte Anzahl Mal und verwirft den Aufruf danach.

Quellen

  1. Baserow Database API documentation, Baserow B.V., abgerufen am 2026-08-26
  2. Baserow database tokens: Secure API authentication, Baserow B.V., abgerufen am 2026-08-26
  3. Curl filter request with space / special characters, Baserow Community, abgerufen am 2026-08-26
  4. API size limit? (Baserow row pagination), Baserow Community, abgerufen am 2026-08-26
  5. Baserow webhooks: Real-time notifications for data changes, Baserow B.V., abgerufen am 2026-08-26
  6. How to set up a webhook to trigger on specific field changes, Baserow B.V. (Blog), abgerufen am 2026-08-26
  7. Install with Docker, Baserow B.V., abgerufen am 2026-08-26
  8. Access token is expired or invalid, Baserow Community, abgerufen am 2026-08-26

Der Content wurde mit Hilfe von KI erstellt, vor allem in der Recherche und Vorformulierung. Prüfung und Abnahme durch unsere Redaktion.