Ich bin ehrlich: Als ein Kunde mich 2023 das erste Mal fragte, Airtable als sein CMS zu nutzen, dachte ich, er macht Witze. Eine Tabellenkalkulations-App betreibt eine Production-Website? Aber nach dem Bau von einem halben Dutzend Websites auf diese Weise — einige mit Astro, einige mit Next.js — bin ich umgeschwenkt. Airtable trifft einen Sweet Spot für bestimmte Projekte, den traditionelle Headless-CMS-Plattformen völlig verfehlen. Dein Marketing-Team kennt sich bereits damit aus. Es ist flexibel genug, um die meisten Inhalte zu modellieren. Und die API ist totenkopfisch einfach.

Aber es hat auch scharfe Kanten. Rate Limits, Attachment-Handling, Eigenheiten relationaler Daten — es gibt viel, das die "Airtable als CMS"-Blog-Beiträge von 2023 dir nie erzählt haben. Dieser Leitfaden deckt alles ab, das ich beim Versand echter Projekte mit diesem Stack in 2026 gelernt habe.

Inhaltsverzeichnis

Using Airtable as a CMS with Astro & Next.js in 2026

Warum Airtable als CMS tatsächlich sinnvoll ist

Das größte Argument für Airtable ist nicht technisch — es ist menschlich. Deine Content-Editoren kennen sich damit bereits aus. Es gibt keine Onboarding-Reibung, kein neues Login zum Vergessen, keine Content-Modeling-UI zum Erlernen. Sie öffnen eine tabellenkalkulationsähnliche Oberfläche, tippen Dinge ein, und es erscheint auf der Website.

Hier ist, was es für bestimmte Anwendungsfälle wirklich gut macht:

  • Null-Lernkurve für Editoren. Wenn jemand Google Sheets verwenden kann, kann er Airtable verwenden.
  • Flexibles Schema. Ein neues Feld hinzufügen dauert fünf Sekunden. Keine Migrationen, keine Schema-Deployments.
  • Built-in Views und Filter. Editoren können gefilterte Views, Kanban-Boards, Galerien erstellen — alles ohne Entwicklerhilfe.
  • Relationale Daten. Im Gegensatz zu flachen Tabellenkalkulationen unterstützt Airtable verknüpfte Datensätze, Lookups und Rollups.
  • Der kostenlose Plan ist großzügig genug. 1.000 Datensätze pro Base und 1.000 API-Aufrufe pro Monat im kostenlosen Plan. Der Team-Plan ($20/Sitz/Monat in 2026) erhöht dich auf 50.000 Datensätze und höhere API-Limits.

Ich habe Airtable als CMS für Portfolio-Websites, Event-Listings, Team-Verzeichnisse, Produktkataloge, Job-Boards und kleine Blogs verwendet. Es funktioniert überraschend gut für alle diese Fälle.

Wann du Airtable NICHT als CMS verwenden solltest

Lass mich dir etwas Schmerz ersparen. Verwende Airtable nicht als dein CMS, wenn:

  • Du mehr als ~10.000 Content-Datensätze hast. Es wird träge, und die API-Paginierung wird bei dieser Größe zu einem echten Kopfschmerz.
  • Du Rich Text mit eingebetteten Komponenten brauchst. Airtables lange Textfelder unterstützen einfaches Markdown, aber du kannst keine React-Komponenten oder benutzerdefinierten Blöcke einbetten wie mit Sanity oder Contentful.
  • Du granulare Berechtigungen für Inhalte brauchst. Airtables Berechtigungsmodell ist pro Base und pro Tabelle, nicht pro Datensatz. Wenn Editor A nicht sehen sollte, was Editor B entwirft, wirst du eine schwere Zeit haben.
  • Du brauchst echte Live-Vorschau. Es gibt keinen eingebauten Draft/Preview-Workflow. Du kannst ihn mit gefilterten Views und einem Status-Feld hacken, aber es ist wackelig.
  • Du brauchst Bildtransformationen. Airtable-Anhang-URLs sind temporär (sie verfallen nach etwa 2 Stunden). Du brauchst eine separate Image-Pipeline.

Für alles über eine kleine bis mittlere Content-Website hinaus wäre dir ein speziell entwickeltes Headless CMS wahrscheinlich besser. Wir behandeln das in unserer Headless-CMS-Entwicklungsarbeit.

Deine Airtable-Base für Inhalte einrichten

Bevor du Code schreibst, richte deine Airtable-Base richtig ein. Hier ist die Struktur, die ich für einen typischen Blog verwende:

Base-Struktur

Erstelle eine Tabelle namens Posts mit diesen Feldern:

Feldname Feldtyp Anmerkungen
Title Single line text Primärfeld
Slug Single line text URL-sicher, Kleinbuchstaben
Body Long text (Markdown) Rich-Text-Formatierung aktivieren
Excerpt Long text Nur Text, 1-2 Sätze
Published Checkbox Filter darauf für Production
Publish Date Date Sortiere danach absteigend
Author Link zu Authors-Tabelle Relationale Verknüpfung
Tags Multiple select Oder Link zu einer Tags-Tabelle
Featured Image Attachment Einzelnes Bild
SEO Title Single line text Optionale Überschreibung
SEO Description Long text Meta-Beschreibung

Erstelle eine gefilterte View namens "Published", die nur Datensätze zeigt, bei denen Published aktiviert ist. Das ist dein Production-Inhalt.

API-Setup

  1. Gehe zu airtable.com/create/tokens und erstelle ein persönliches Zugriffstoken.
  2. Gib ihm data.records:read Bereich (und data.records:write wenn du Schreibzugriff brauchst).
  3. Beschränke es auf die spezifische Base, die du verwendest.
  4. Speichere das Token in deiner .env Datei. Committe es nie.
# .env
AIRTABLE_TOKEN=pat_xxxxxxxxxxxxx
AIRTABLE_BASE_ID=appXXXXXXXXXXXXXX

Du kannst deine Base-ID in der Airtable-API-Dokumentation oder in der URL finden, wenn du deine Base anschaust.

Using Airtable as a CMS with Astro & Next.js in 2026 - architecture

Airtable mit Astro verbinden

Astro ist mein bevorzugter Framework für Airtable-betriebene Websites, wenn der Inhalt größtenteils statisch ist. Da Astro standardmäßig auf statisches HTML erstellt, rufst du alle deine Airtable-Daten zur Build-Zeit ab, was bedeutet, dass null API-Aufrufe von deinen Besuchern erfolgen und keine Rate-Limit-Bedenken in Production.

Wenn du Astro für dein nächstes Projekt erkundest, haben wir tiefe Erfahrung damit — schau dir unsere Astro-Entwicklungsdienste an.

SDK installieren

npm install airtable

Erstelle ein Datenabruf-Dienstprogramm

// src/lib/airtable.ts
import Airtable from 'airtable';

const base = new Airtable({ apiKey: import.meta.env.AIRTABLE_TOKEN })
  .base(import.meta.env.AIRTABLE_BASE_ID);

export interface Post {
  id: string;
  title: string;
  slug: string;
  body: string;
  excerpt: string;
  publishDate: string;
  featuredImage: { url: string; filename: string } | null;
  tags: string[];
}

export async function getPosts(): Promise<Post[]> {
  const records = await base('Posts')
    .select({
      view: 'Published',
      sort: [{ field: 'Publish Date', direction: 'desc' }],
    })
    .all();

  return records.map((record) => ({
    id: record.id,
    title: record.get('Title') as string,
    slug: record.get('Slug') as string,
    body: record.get('Body') as string,
    excerpt: record.get('Excerpt') as string,
    publishDate: record.get('Publish Date') as string,
    featuredImage: record.get('Featured Image')
      ? {
          url: (record.get('Featured Image') as any[])[0].url,
          filename: (record.get('Featured Image') as any[])[0].filename,
        }
      : null,
    tags: (record.get('Tags') as string[]) || [],
  }));
}

export async function getPostBySlug(slug: string): Promise<Post | undefined> {
  const records = await base('Posts')
    .select({
      view: 'Published',
      filterByFormula: `{Slug} = '${slug}'`,
      maxRecords: 1,
    })
    .all();

  if (records.length === 0) return undefined;
  const record = records[0];

  return {
    id: record.id,
    title: record.get('Title') as string,
    slug: record.get('Slug') as string,
    body: record.get('Body') as string,
    excerpt: record.get('Excerpt') as string,
    publishDate: record.get('Publish Date') as string,
    featuredImage: record.get('Featured Image')
      ? {
          url: (record.get('Featured Image') as any[])[0].url,
          filename: (record.get('Featured Image') as any[])[0].filename,
        }
      : null,
    tags: (record.get('Tags') as string[]) || [],
  };
}

Verwende es in Astro-Seiten

---
// src/pages/blog/[slug].astro
import { getPosts, getPostBySlug } from '../../lib/airtable';
import Layout from '../../layouts/Layout.astro';

export async function getStaticPaths() {
  const posts = await getPosts();
  return posts.map((post) => ({
    params: { slug: post.slug },
  }));
}

const { slug } = Astro.params;
const post = await getPostBySlug(slug!);

if (!post) return Astro.redirect('/404');
---

<Layout title={post.title}>
  <article>
    <h1>{post.title}</h1>
    <time>{post.publishDate}</time>
    <div set:html={post.body} />
  </article>
</Layout>

Das ist alles. Bei astro build wird jeder Beitrag aus Airtable abgerufen und in statisches HTML gerendert. Deine Production-Website macht null API-Aufrufe.

Airtable mit Next.js verbinden

Next.js gibt dir mehr Flexibilität. Du kannst zur Build-Zeit mit generateStaticParams abrufen, zur Request-Zeit mit Server-Komponenten, oder ISR (Incremental Static Regeneration) für das Beste aus beiden Welten verwenden.

Wir erstellen viele Next.js-Websites — es ist unser Kerngeschäft. Sieh dir unsere Next.js-Entwicklungsfähigkeiten an.

Das Fetch-Dienstprogramm (Next.js-Version)

Ich bevorzuge es, die Airtable REST API direkt mit fetch in Next.js zu verwenden, anstatt das SDK zu verwenden. Es gibt dir bessere Kontrolle über das Caching mit Next.js erweiterten fetch-Optionen.

// lib/airtable.ts
const AIRTABLE_TOKEN = process.env.AIRTABLE_TOKEN!;
const AIRTABLE_BASE_ID = process.env.AIRTABLE_BASE_ID!;

const headers = {
  Authorization: `Bearer ${AIRTABLE_TOKEN}`,
  'Content-Type': 'application/json',
};

export async function fetchPosts() {
  const url = new URL(
    `https://api.airtable.com/v0/${AIRTABLE_BASE_ID}/Posts`
  );
  url.searchParams.set('view', 'Published');
  url.searchParams.set('sort[0][field]', 'Publish Date');
  url.searchParams.set('sort[0][direction]', 'desc');

  const res = await fetch(url.toString(), {
    headers,
    next: { revalidate: 60 }, // ISR: revalidate every 60 seconds
  });

  if (!res.ok) throw new Error(`Airtable API error: ${res.status}`);

  const data = await res.json();
  return data.records.map((record: any) => ({
    id: record.id,
    title: record.fields['Title'],
    slug: record.fields['Slug'],
    body: record.fields['Body'],
    excerpt: record.fields['Excerpt'],
    publishDate: record.fields['Publish Date'],
    tags: record.fields['Tags'] || [],
  }));
}

ISR-Seite mit App Router

// app/blog/[slug]/page.tsx
import { fetchPosts } from '@/lib/airtable';
import { notFound } from 'next/navigation';

export async function generateStaticParams() {
  const posts = await fetchPosts();
  return posts.map((post: any) => ({ slug: post.slug }));
}

export default async function BlogPost({
  params,
}: {
  params: Promise<{ slug: string }>;
}) {
  const { slug } = await params;
  const posts = await fetchPosts();
  const post = posts.find((p: any) => p.slug === slug);

  if (!post) notFound();

  return (
    <article>
      <h1>{post.title}</h1>
      <time>{post.publishDate}</time>
      <div dangerouslySetInnerHTML={{ __html: post.body }} />
    </article>
  );
}

Mit revalidate: 60 wird Next.js die gecachte Seite bedienen und sie im Hintergrund höchstens einmal alle 60 Sekunden aktualisieren. Deine Editoren aktualisieren Airtable, und die Website aktualisiert sich innerhalb einer Minute. Kein Webhook-Setup, kein Rebuild-Trigger.

Bilder und Anhänge handhaben

Das ist der größte Fallstrick bei Airtable als CMS. Airtable-Anhang-URLs verfallen. Sie sind signierte URLs, die nach etwa 2 Stunden ungültig werden. Wenn du sie direkt in deinem HTML renderst, werden sie kaputt gehen.

Hier sind deine Optionen:

Option 1: Bei der Build-Zeit herunterladen (Astro)

Für statische Websites Bilder während des Builds herunterladen und lokal bereitstellen:

import fs from 'fs/promises';
import path from 'path';

async function downloadImage(url: string, filename: string) {
  const res = await fetch(url);
  const buffer = Buffer.from(await res.arrayBuffer());
  const outputPath = path.join('public', 'images', 'cms', filename);
  await fs.mkdir(path.dirname(outputPath), { recursive: true });
  await fs.writeFile(outputPath, buffer);
  return `/images/cms/${filename}`;
}

Option 2: Durch ein CDN proxy

Richte einen Cloudflare Worker oder Vercel Edge Function ein, der Airtable-Bild-URLs proxy, sie cached und durch deine eigene Domain bereitstellt. Dies funktioniert für Astro und Next.js.

Option 3: Nutze einen separaten Image-Host

Lade Bilder zu Cloudinary, Imgix oder einem S3-Bucket hoch, und speichere die permanente URL in einem Textfeld, anstatt Airtables Attachment-Feld zu verwenden. Das ist, was ich für Production-Websites empfehle — es ist der zuverlässigste Ansatz.

Caching, Rate Limits und Performance

Airtables API hat strenge Rate Limits: 5 Anfragen pro Sekunde pro Base. Das ist nicht viel. So bleibst du gut darunter.

Strategie Framework Wie es funktioniert
Statische Generierung Astro Alle API-Aufrufe finden zur Build-Zeit statt. Null Runtime-Aufrufe.
ISR Next.js Gecachte Responses, revalidiert auf einem Timer.
In-Memory-Cache Beide Cache API-Responses in einer Map mit TTL.
Webhook + Rebuild Beide Airtable-Automatisierung löst einen Vercel/Netlify Rebuild aus.
Redis/KV Cache Next.js (Vercel) Speichere API-Responses in Vercel KV oder Upstash Redis.

Für Astro-Websites bedeutet der Build-Zeit-Ansatz, dass du die API nur während Deployments triffst. Für Next.js mit ISR wirst du sie höchstens einmal pro Revalidierungsintervall pro Seite treffen.

Wenn du viele Seiten und kurze Revalidierungsintervalle hast, erwäge das Abrufen aller Datensätze auf einmal und das Caching des gesamten Datensatzes, anstatt pro-Seite API-Aufrufe zu machen.

Paginierung ist wichtig

Airtable gibt maximal 100 Datensätze pro Anfrage zurück. Die .all() Methode im SDK behandelt Paginierung automatisch, aber wenn du fetch direkt verwendest, musst du dem offset Token folgen:

async function fetchAllRecords(tableName: string) {
  let allRecords: any[] = [];
  let offset: string | undefined;

  do {
    const url = new URL(
      `https://api.airtable.com/v0/${AIRTABLE_BASE_ID}/${tableName}`
    );
    url.searchParams.set('view', 'Published');
    if (offset) url.searchParams.set('offset', offset);

    const res = await fetch(url.toString(), { headers });
    const data = await res.json();

    allRecords = [...allRecords, ...data.records];
    offset = data.offset;
  } while (offset);

  return allRecords;
}

Rich Text und Markdown-Inhalte

Airtables lange Textfelder können Markdown speichern, wenn du die Option "Rich Text" aktivierst. Aber was du von der API zurückbekommst, ist Markdown-formatierter Text, nicht HTML.

Du musst ihn konvertieren. Ich verwende marked für einfache Fälle oder unified mit remark Plugins für mehr Kontrolle:

import { marked } from 'marked';

const htmlContent = marked.parse(post.body);

Für Astro kannst du auch die eingebaute Markdown-Verarbeitung verwenden:

---
import { marked } from 'marked';
const html = marked.parse(post.body);
---
<article set:html={html} />

Eine Sache, auf die du achten solltest: Airtables Rich-Text-Editor produziert seinen eigenen Markdown-Geschmack. Es behandelt fett, kursiv, Links, Überschriften und Listen gut. Code-Blöcke und Tabellen werden unterstützt, können aber knifflig sein. Wenn dein Inhalt komplexe Formatierung benötigt, erwäge, dass Editoren im reinen Markdown-Modus schreiben.

Airtable vs traditionelle Headless-CMS-Optionen

Lassen Sie uns ehrlich über die Trade-offs sprechen. Hier ist, wie Airtable gegen speziell entwickelte Headless-CMS-Plattformen im Jahr 2026 steht:

Feature Airtable Sanity Contentful Strapi
Editor-Lernkurve Sehr niedrig Mittel Mittel Mittel
Content-Modellierung Flexibel, informell Ausgezeichnet Ausgezeichnet Gut
API-Rate-Limits 5 Anfragen/s pro Base Großzügig (CDN) Großzügig (CDN) Self-Hosted
Bildbehandlung Ablaufende URLs Built-in CDN Built-in CDN Self-Hosted
Vorschau/Entwürfe Manuell (Checkbox) Built-in Built-in Built-in
Preis (Team von 5) $100/Monat (Team) Kostenlos-Stufe möglich $300/Monat+ Kostenlos (Self-Host)
Webhook-Unterstützung Via Automationen Built-in Built-in Built-in
Rich-Text-Qualität Basis-Markdown Portable Text Strukturiert Rich Text
Relationaler Inhalt Verknüpfte Datensätze Referenzen Referenzen Relationen

Airtable gewinnt bei Editor-Erlebnis und Flexibilität. Es verliert bei Bildbehandlung, Vorschau-Workflows und API-Zuverlässigkeit bei Skalierung. Für kleine bis mittlere Websites, bei denen deine Editoren bereits in Airtable sind? Es ist eine solide Wahl. Für inhaltsreiche Websites mit komplexen Workflows? Gehe zu einem echten CMS.

Real-World-Architekturmuster

Hier sind die Muster, die ich in Production verwendet habe:

Muster 1: Vollständig statisch mit Astro + Rebuild-Webhooks

Best für: Marketing-Websites, Portfolios, Verzeichnisse mit < 500 Datensätzen.

  1. Astro ruft alle Airtable-Daten zur Build-Zeit ab.
  2. Airtable-Automatisierung sendet einen Webhook an Vercel/Netlify bei Datensatz-Update.
  3. Website wird in 30-60 Sekunden neuaufgebaut.
  4. Bilder zur Build-Zeit heruntergeladen — keine ablaufenden URL-Probleme.

Muster 2: ISR mit Next.js

Best für: Blogs, Kataloge, Websites mit häufigen Updates.

  1. Next.js generiert Seiten mit ISR (alle 60-300 Sekunden revalidieren).
  2. Airtable API wird höchstens einmal pro Revalidierung pro eindeutiger Seite aufgerufen.
  3. Bilder über Cloudinary oder auf ein CDN heruntergeladen.
  4. Editoren sehen Updates innerhalb von Minuten ohne vollständigen Rebuild auszulösen.

Muster 3: Airtable + Zusätzliches CMS

Best für: Websites, bei denen einige Inhalte in Airtable und andere Inhalte bessere Bearbeitung benötigen.

  1. Strukturierte Daten (Team-Mitglieder, Events, Produkte) bleiben in Airtable.
  2. Long-Form-Inhalte (Blog-Beiträge, Case Studies) gehen zu Sanity oder Notion.
  3. Frontend ruft von beiden Quellen zur Build-Zeit oder mit ISR ab.

Dieser Hybrid-Ansatz ist häufiger als man denken würde. Wir haben mehrere Websites auf diese Weise erstellt — wenn du etwas Ähnliches in Betracht ziehst, lass uns darüber sprechen.

Rebuilds von Airtable aus auslösen

Airtable hat integrierte Automatisierungen, die Webhooks auslösen können. Richte einen Trigger auf "When a record is updated" in deiner Posts-Tabelle ein, dann sende eine POST-Anfrage an den Build-Hook deiner Deployment-Plattform:

// Vercel Deploy Hook
https://api.vercel.com/v1/integrations/deploy/prj_xxxx/yyyy

// Netlify Build Hook
https://api.netlify.com/build_hooks/xxxxxxxxxxxx

Füge eine 30-Sekunden-Verzögerung in der Automatisierung hinzu, um schnelle Edits zu bündeln.

FAQ

Ist Airtable kostenlos als CMS zu verwenden?

Airtables kostenloser Plan umfasst 1.000 Datensätze pro Base und 1.000 API-Aufrufe pro Monat. Das ist genug für eine kleine Website, aber du wirst wahrscheinlich den Team-Plan ($20/Sitz/Monat im Jahr 2026) für irgendetwas Ernstes brauchen. Der Team-Plan gibt dir 50.000 Datensätze und höhere API-Limits.

Wie handle ich Airtables ablaufende Bild-URLs?

Airtable-Anhang-URLs verfallen nach etwa 2 Stunden. Für statische Websites, die mit Astro erstellt wurden, laden Sie Bilder zur Build-Zeit herunter. Für Next.js mit ISR, entweder proxy Bilder durch ein CDN wie Cloudinary, oder speichere Bild-URLs in einem separaten Image-Hosting-Service und referenziere sie als Textfelder in Airtable.

Kann Airtable einen Blog mit Hunderten von Beiträgen handhaben?

Ja, bis zu einem Punkt. Airtable handhabt Hunderte von Datensätzen gut. Sobald du in die Tausende gehst, werden API-Paginierung und Build-Zeiten merklich. Für einen Blog mit unter 1.000 Beiträgen funktioniert es gut. Darüber hinaus solltest du ein dediziertes Headless-CMS in Betracht ziehen.

Ist Airtable besser als Notion als CMS?

Sie lösen unterschiedliche Probleme. Airtable ist besser für strukturierte Daten (Produkte, Events, Team-Mitglieder) wegen seines relationalen Datenbankmodells. Notion ist besser für lange geschriebene Inhalte wegen seines Block-basierten Editors. Airtables API ist auch reifer und schneller als Notions.

Wie richte ich Preview/Draft-Funktionalität mit Airtable ein?

Füge ein "Status" Single-Select-Feld mit Optionen wie "Draft", "In Review" und "Published" hinzu. Erstelle eine gefilterte View für jeden Status. Deine Production-Website ruft aus der "Published" View ab. Für Vorschau, erstelle eine separate Preview-Route, die aus der "In Review" View abruft, geschützt durch Authentifizierung.

Sollte ich das Airtable SDK oder die REST API direkt verwenden?

Für Astro funktioniert das offizielle airtable npm-Paket gut, da du zur Build-Zeit abrufst. Für Next.js empfehle ich die Verwendung von fetch direkt mit der REST API — es gibt dir Kontrolle über Next.js Cache-Direktiven wie revalidate und tags. Das SDK versteht Next.js's erweiterte fetch Optionen nicht.

Was ist das maximale API-Aufruflimit von Airtable?

Airtable setzt ein Rate Limit von 5 Anfragen pro Sekunde pro Base durch. Dies überschreiten gibt einen 429-Status-Code zurück. Im Team-Plan erhältst du ein höheres monatliches Aufruf-Allowance, aber das pro-Sekunde-Rate-Limit bleibt gleich. Statische Generierung und ISR sind die besten Wege, um die API-Nutzung zu minimieren.

Kann ich Airtable mit Astro und Next.js im selben Projekt verwenden?

Nicht genau im selben Projekt, aber du kannst mehrere Frontends haben, die eine gemeinsame Airtable-Base antreiben. Einige Teams verwenden Astro für ihre Marketing-Website und Next.js für ihre Web-App, beide lesen aus derselben Airtable-Base. Beachte einfach die gemeinsamen Rate Limits über alle Consumer hinweg.