Kamaankamaan

Headless CMS Next.js Integration: Schritt-für-Schritt-Setup vom Nullpunkt zum Live-Blog

Die meisten Next.js-Tutorials gehen davon aus, dass du ein CMS hast. Diese Anleitung zeigt die Verdrahtung von null: Fetch-Helper, App Router Seiten, generateStaticParams, ISR und mehrsprachige Routen für Kamaan, in unte

Junaid Khalid
Junaid Khalid
29. Mai 2026 · 11 min read

Die meisten Next.js-Blog-Tutorials gehen davon aus, dass du bereits ein CMS ausgewählt hast. Dieses zeigt die Verdrahtung von null an. Du siehst die genauen Dateien, die genauen fetch-Aufrufe und die genauen Deploy-Schritte, die dich von einem leeren Next.js-Projekt zu einem Live-Blog bringen, der Inhalte aus Kamaan liest. Das Ziel ist eine funktionierende /blog-Route, funktionierende /blog/[slug]-Seiten, mehrsprachige Routen und ISR-Caching, in unter sechzig Minuten.

Auf einen Blick

  • Eine Next.js + Kamaan Integration braucht etwa sechs Dateien: einen fetch-Helper, die next.config.js Bildkonfiguration, eine Listenseite, eine Einzelpost-Seite, eine ISR-Konfiguration und eine mehrsprachige Variante.
  • Die Kamaan REST API liefert JSON mit id, title, slug, content, excerpt, featured_image_url und language. Kein GraphQL, kein SDK, keine Auth-Header für veröffentlichten Inhalt.
  • App Router ist die empfohlene Form, weil generateStaticParams und revalidate dir ISR ohne zusätzliche Verdrahtung geben.
  • Das Eintragen von Bilddomains in next.config.js ist der häufigste Grund, warum Builds scheitern, nachdem der erste fetch funktioniert.
  • Mehrsprachige Blogs brauchen nur ein zusätzliches Routensegment ([lang]) und einen Query-Parameter beim fetch-Aufruf.

Warum es diese Anleitung gibt

Bestehende Next.js-Blog-Tutorials beginnen meist mit "installiere zuerst Contentful" oder "installiere zuerst Sanity". Sie überspringen den Teil, in dem du CMS-Optionen vergleichst, und dann den Teil, in dem du die Routing-Schicht baust. Das hinterlässt eine Lücke: Entwickler, die Next.js schon kennen, aber ein Content-Backend wollen, das keine Schema-Migration, keinen GraphQL-Playground und kein Config-Repo braucht.

Kamaan füllt diese Lücke. Es ist ein Headless CMS mit REST API Delivery, eingebauter Auto-Multilingual Delivery und einem MCP Server Endpunkt, damit Claude oder ChatGPT direkt in deinen Blog schreiben können. Auf der Next.js-Seite hat die Integration die gleiche Form wie Contentful oder Sanity: JSON fetchen, Markdown rendern, ISR konfigurieren. Der Unterschied ist, was du dir sparst: keine SDK-Installation, keine Token-Rotation für Lesezugriff, keine Schema-Datei. Du liest Artikel über Site-ID und Slug.

Wenn du dich noch entscheidest, welches CMS du nutzen sollst, lies zuerst Was ist ein Headless CMS und Bestes Headless CMS für Startups. Wenn du dich schon für Kamaan entschieden hast, ist der Rest dieser Anleitung für dich.

Hier ist die Setup-Karte auf einen Blick, bevor du Zeit in die Verdrahtung steckst.

Next.js plus Headless CMS Karte mit App Router, ISR und mehrsprachigen Routen Setup

Benchmark der Setup-Zeit

Auf der Kamaan-Seite dauert das Veröffentlichen deines ersten Posts etwa 14 Minuten (Konto, Site, erster Artikel, Sprachen live). Auf der Next.js-Seite ist das Verdrahten der sechs Dateien unten ungefähr 40 bis 60 Minuten für einen Entwickler, der das zum ersten Mal macht. Die Aufschlüsselung:

Schritt Was läuft Wo es läuft Geschätzte Zeit
1. Fetch-Helper lib/kamaan.ts Server 5 min
2. Env-Variablen + Bildkonfiguration .env.local, next.config.js Build-Zeit 5 min
3. Listenansicht app/blog/page.tsx Server Component 10 min
4. Einzelpost app/blog/[slug]/page.tsx + generateStaticParams Build + Revalidate 15 min
5. ISR-Konfiguration export const revalidate = 60 Edge- oder Node-Runtime 5 min
6. Mehrsprachige Route app/[lang]/blog/[slug]/page.tsx Server Component 20 min

Die fünfzehn Minuten in Schritt 4 umfassen das Markdown-Rendering und die Verarbeitung des Featured Image, wo die meisten Projekte hängenbleiben. Wenn du die Mehrsprachigkeit überspringst, lieferst du in vierzig Minuten aus. Die Arbeit im Kamaan-Dashboard selbst (die Site anlegen, den ersten Artikel verfassen, den Übersetzungen beim Eintreffen zusehen) ist der auf kamaan.io zitierte ~14-min Benchmark.

Schritt 1: Fetch-Helper

Lege lib/kamaan.ts an. Diese Datei ist der einzige Ort, der die Form von Kamaans REST-API kennt. Jede andere Datei importiert von hier.

const BASE = "https://api.kamaan.io/v1";
const SITE_ID = process.env.NEXT_PUBLIC_KAMAAN_SITE_ID;

export type Article = {
  id: string;
  title: string;
  slug: string;
  content: string;
  excerpt: string;
  featured_image_url: string | null;
  language: string;
  published_at: string;
};

export async function listArticles(lang = "de"): Promise<Article[]> {
  const res = await fetch(
    `${BASE}/sites/${SITE_ID}/articles?language=${lang}&status=published`,
    { next: { revalidate: 60 } }
  );
  if (!res.ok) throw new Error(`Kamaan list failed: ${res.status}`);
  const data = await res.json();
  return data.articles;
}

export async function getArticleBySlug(slug: string, lang = "de"): Promise<Article | null> {
  const res = await fetch(
    `${BASE}/sites/${SITE_ID}/articles/by-slug/${slug}?language=${lang}`,
    { next: { revalidate: 60 } }
  );
  if (res.status === 404) return null;
  if (!res.ok) throw new Error(`Kamaan article failed: ${res.status}`);
  const data = await res.json();
  return data.article;
}

Zwei Dinge zum Beachten. Erstens sagt der next: { revalidate: 60 }-Hinweis Next.js, die Antwort 60 Sekunden zu cachen. Das ist deine ISR-Schicht gratis, ohne separate Konfiguration. Zweitens brauchst du keinen Auth-Header für veröffentlichten Inhalt. Wenn du Entwürfe ziehen willst, fügst du einen Authorization: Bearer <token>-Header hinzu. Das Token liegt in .env.local, niemals in NEXT_PUBLIC_*.

Schritt 2: Umgebungsvariablen und Bilddomains

Lege .env.local an:

NEXT_PUBLIC_KAMAAN_SITE_ID=6a15f18577639d2385209d06

Dann öffne next.config.js und füge die Kamaan-Bilddomain zu images.remotePatterns hinzu. Das ist der häufigste Build-Fehler. Die Fehlermeldung lautet Invalid src prop on next/image, hostname "cdn.kamaan.io" is not configured under images in your next.config.js.

/** @type {import('next').NextConfig} */
const nextConfig = {
  images: {
    remotePatterns: [
      { protocol: "https", hostname: "cdn.kamaan.io" },
      { protocol: "https", hostname: "images.kamaan.io" },
    ],
  },
};

module.exports = nextConfig;

Starte den Dev-Server nach dem Bearbeiten von next.config.js neu. Hot Reload erkennt Änderungen an der Bildkonfiguration nicht.

Schritt 3: Die Listenansicht

app/blog/page.tsx liest alle veröffentlichten Artikel und rendert Karten. Server Component, kein Client-State nötig.

import Link from "next/link";
import Image from "next/image";
import { listArticles } from "@/lib/kamaan";

export const revalidate = 60;

export default async function BlogIndex() {
  const articles = await listArticles("de");
  return (
    <main className="mx-auto max-w-3xl px-6 py-12">
      <h1 className="text-4xl font-bold mb-8">Blog</h1>
      <ul className="space-y-8">
        {articles.map((a) => (
          <li key={a.id}>
            <Link href={`/blog/${a.slug}`}>
              {a.featured_image_url && (
                <Image src={a.featured_image_url} alt={a.title} width={800} height={420} />
              )}
              <h2 className="text-2xl font-semibold mt-4">{a.title}</h2>
              <p className="text-gray-600 mt-2">{a.excerpt}</p>
            </Link>
          </li>
        ))}
      </ul>
    </main>
  );
}

export const revalidate = 60 auf Seitenebene ist Gürtel-und-Hosenträger neben dem revalidate auf fetch-Ebene. Eines davon allein funktioniert. Beide zusammen sind auch in Ordnung und machen die Absicht klar für jeden, der die Datei später liest.

Schritt 4: Die Einzelpost-Seite

app/blog/[slug]/page.tsx liest einen Artikel über den Slug, gibt 404 zurück, wenn er fehlt, und rendert Markdown. An dieser Datei hängen die meisten Projekte, weil drei Dinge zusammenpassen müssen: der dynamische Routen-Parameter, die Static-Params-Generierung und der Markdown-Renderer.

import { notFound } from "next/navigation";
import Image from "next/image";
import { remark } from "remark";
import html from "remark-html";
import { getArticleBySlug, listArticles } from "@/lib/kamaan";

export const revalidate = 60;

export async function generateStaticParams() {
  const articles = await listArticles("de");
  return articles.map((a) => ({ slug: a.slug }));
}

export default async function ArticlePage({ params }: { params: { slug: string } }) {
  const article = await getArticleBySlug(params.slug, "de");
  if (!article) notFound();
  const processed = await remark().use(html).process(article.content);
  const contentHtml = processed.toString();
  return (
    <article className="mx-auto max-w-3xl px-6 py-12">
      <h1 className="text-4xl font-bold">{article.title}</h1>
      {article.featured_image_url && (
        <Image src={article.featured_image_url} alt={article.title} width={1200} height={630} className="my-6 rounded-lg" />
      )}
      <div className="prose mt-8" dangerouslySetInnerHTML={{ __html: contentHtml }} />
    </article>
  );
}

generateStaticParams läuft zur Build-Zeit. Es zieht jeden veröffentlichten Slug, damit Next.js jeden Post als statisches HTML vorrendern kann. Neue Artikel, die nach dem Deploy veröffentlicht werden, funktionieren trotzdem dank ISR: Die erste Anfrage trifft die API, cached das Ergebnis 60 Sekunden und liefert allen anderen das gecachte HTML.

Installiere die Markdown-Abhängigkeiten:

npm i remark remark-html

Wenn du MDX bevorzugst, tausche remark-html gegen @next/mdx und passe die Komponentenform an. Die meisten Blogs brauchen kein MDX. Reines Markdown plus die Tailwind-Klasse prose deckt 90% der Fälle ab.

Schritt 5: ISR, Cache-Invalidierung und der Haken

revalidate = 60 bedeutet, dass eine Post-Änderung innerhalb von 60 Sekunden nach der nächsten Anfrage sichtbar wird. Für die meisten Blogs reicht das. Wenn du sofortige Veröffentlichung willst, zwei Wege:

  1. Setze revalidate auf ein längeres Intervall und löse On-Demand-Revalidierung über einen Kamaan-Webhook aus. Kamaan kann an https://deinedomain.com/api/revalidate?secret=xxx&path=/blog/[slug] POSTen, sobald ein Artikel veröffentlicht wird. Dein Route-Handler ruft revalidatePath() auf und gibt 200 zurück.
  2. Nutze revalidate = 0 (SSR bei jeder Anfrage). Langsamer für Nutzer, keine Cache-Schicht, aber immer frisch.

Die meisten Teams wählen Option 1, sobald der Traffic wächst. Bis dahin ist revalidate = 60 in Ordnung.

Ehrlicher Hinweis: Vercels Data Cache und der Full Route Cache von Next.js invalidieren sich nicht immer zusammen. Wenn du einen Artikel änderst und die neue Version unter /blog/[slug] erscheint, aber der alte Excerpt auf /blog bleibt, ist das der Full Route Cache der Index-Seite, der nachhängt. Triggere revalidate sowohl für /blog als auch für /blog/[slug] aus dem gleichen Webhook.

Schritt 6: Mehrsprachige Routen

Hier spart Kamaan am meisten Zeit. Kamaans automatische mehrsprachige Auslieferung bedeutet, dass ein POST einen Artikel auf Englisch anlegt und Übersetzungen ins Spanische, Deutsche, Französische und Italienische am gleichen Slug unter einem language-Query-Parameter verfügbar sind. Deine Next.js-Seite behandelt das Routensegment.

Verschiebe deine Blog-Seiten unter app/[lang]/blog/. Füge Sprachvalidierung in der Route hinzu:

const SUPPORTED = ["en", "es", "de", "fr", "it"] as const;
type Lang = (typeof SUPPORTED)[number];

export async function generateStaticParams() {
  const params = [];
  for (const lang of SUPPORTED) {
    const articles = await listArticles(lang);
    for (const a of articles) {
      params.push({ lang, slug: a.slug });
    }
  }
  return params;
}

export default async function ArticlePage({ params }: { params: { lang: Lang; slug: string } }) {
  if (!SUPPORTED.includes(params.lang)) notFound();
  const article = await getArticleBySlug(params.slug, params.lang);
  if (!article) notFound();
  // ... rendern wie zuvor
}

Die Slugs bleiben in allen Sprachen englisch. Das ist eine bewusste SEO-Entscheidung: Sie hält deine URL-Struktur konsistent, vereinfacht die Analytik und passt zu dem, was jeder große SaaS-Blog macht (Stripe, Notion, Linear). Wenn du übersetzte Slugs brauchst, speichere sie in einer Slug-Map und löse sie in Middleware auf. Die meisten Teams tun das nicht.

Hier ist der sechsschrittige Setup-Prozess auf ein Bild gebracht, das du beim Bauen offen lassen kannst.

Sechs-Schritt Next.js plus Kamaan Integrationsflow: Fetch-Helper, Env-Konfig, Listenansicht, Einzelpost, ISR, mehrsprachige Route

Szenarien aus der Praxis

Szenario 1: B2B-SaaS-Blog, 40 Posts, Englisch plus Spanisch

Ein Zwei-Personen-Team migrierte von einem Markdown-im-Repo-Blog zu Kamaan, weil jedes Content-Update einen Deploy erforderte. Das Setup kostete den Senior Engineer 50 Minuten mit dieser Anleitung. Die spanische Version aller 40 Posts wurde automatisch von Kamaans Auto-Multilingual Delivery erzeugt. Gesamtzeit inklusive Übersetzungen: 70 Minuten. Der Deploy war sofort, weil die bestehende Next.js-App bereits auf Vercel lief.

Szenario 2: Solo-Founderin, noch keine Posts, mehrsprachig vom ersten Tag an

Eine Solo-Entwicklerin wollte ab Launch Englisch plus vier Sprachen. Sie übersprang die Markdown-im-Repo-Phase komplett. Setup waren 45 Minuten auf der Next.js-Seite und 15 Minuten für den ersten Artikel (in Kamaan geschrieben, auto-übersetzt, veröffentlicht). Der MCP Server Endpunkt ließ sie weitere Artikel schreiben, indem sie mit Claude sprach, das direkt in Kamaan postete.

Deployment auf Vercel

Drei Schritte:

  1. Push das Repo zu GitHub.
  2. Importiere in Vercel. Vercel erkennt Next.js automatisch.
  3. Füge NEXT_PUBLIC_KAMAAN_SITE_ID zu den Umgebungsvariablen von Vercel hinzu. Erneut deployen.

Das ist das gesamte Deployment. ISR funktioniert auf Vercel out of the box. Der Build führt generateStaticParams aus, rendert jeden Artikel vor, und die Runtime behandelt neue Artikel über den revalidate-Hinweis.

Wenn du anderswo deployst (Netlify, Cloudflare Pages, eigener Node-Server), variiert die ISR-Semantik. Cloudflare Pages mit @cloudflare/next-on-pages funktioniert, nutzt aber KV als Cache-Schicht. Selbst gehostete Node-Server brauchen den Standalone-Output-Modus und ein persistentes Dateisystem, damit der Cache Neustarts überlebt. Vercel ist der Weg mit der geringsten Reibung.

FAQ

Wie lange dauert ein Next.js plus Kamaan Setup tatsächlich?

Vierzig bis sechzig Minuten für einen erfahrenen Next.js-Entwickler mit dieser Anleitung. Die größte Zeitsenke ist Markdown-Rendering, das etwa zehn Minuten dazugibt, wenn du es vorher nicht gemacht hast. Mehrsprachigkeit gibt weitere zwanzig.

Brauche ich TypeScript?

Nein. Jedes Beispiel hier funktioniert genauso in reinem JavaScript. Der Article-Typ ist Dokumentation, keine Laufzeit-Anforderung. Die meisten Teams, die Next.js nutzen, nutzen schon TypeScript, deshalb gehen die Beispiele davon aus.

Kann ich Pages Router statt App Router nutzen?

Ja. Der Fetch-Helper bleibt identisch. Ersetze app/blog/page.tsx durch pages/blog/index.tsx, nutze getStaticProps für den Index und getStaticParams plus getStaticProps mit revalidate: 60 für den Einzelpost. App Router wird für neue Projekte empfohlen, weil die ISR-Ergonomie sauberer ist.

Was ist mit RSS, Sitemap und Open Graph?

Kamaan generiert RSS automatisch unter https://api.kamaan.io/v1/sites/{site_id}/rss. Die Sitemap ist unter /sites/{site_id}/sitemap.xml. Beide aktualisieren sich, sobald du veröffentlichst. Für Open Graph setze Titel, Beschreibung und featured_image_url in den SEO-Feldern von Kamaan und lies sie in deiner Next.js-Funktion generateMetadata.

Wie zeige ich Entwürfe vorab?

Gib einen Authorization: Bearer <token>-Header beim fetch-Aufruf mit und füge &status=draft an die URL an. Die meisten Teams schützen das hinter einer /blog/preview/[slug]-Route mit einem geheimen Cookie. Kamaans API unterstützt Preview-Tokens direkt, sodass du keinen eigenen bauen musst.

Was, wenn ich später ein CMS wie Contentful oder Sanity hinzufügen will?

Nur der Fetch-Helper ändert sich. Tausche die API-URL und das JSON-Parsing, lasse die Seiten-Dateien gleich. Das ist der Wert davon, das CMS als JSON-Quelle statt als SDK-Abhängigkeit zu behandeln.

Funktioniert das mit React Server Components?

Ja. Jedes Beispiel oben ist eine Server Component. Keine "use client"-Direktive nötig, außer du fügst interaktive Widgets wie eine Suchleiste hinzu.

Kann ich das ohne Vercel betreiben?

Ja, mit Einschränkungen. Cloudflare Pages, Netlify, AWS Amplify und selbst gehostetes Node unterstützen Next.js. ISR funktioniert out of the box auf Vercel und Cloudflare. Auf Netlify braucht ISR deren On-Demand Builders. Selbst gehostet braucht den Standalone-Output-Modus.

Verwandt auf Kamaan

Mit Kamaan loslegen

Ein Next.js plus Kamaan Blog sind sechs Dateien und eine Stunde Arbeit. Melde dich bei Kamaan an, lege eine Site an, kopiere die Site-ID und folge dieser Anleitung. Wenn du bei Bilddomains oder ISR-Caching hängenbleibst, decken die Docs beides mit Beispielprojekten ab, die du forken kannst.

Frequently asked

FAQ · 8 ITEMS
Wie lange dauert ein Next.js plus Kamaan Setup tatsächlich?

Vierzig bis sechzig Minuten für einen erfahrenen Next.js-Entwickler mit dieser Anleitung. Die größte Zeitsenke ist Markdown-Rendering, das etwa zehn Minuten dazugibt, wenn du es vorher nicht gemacht hast. Mehrsprachigkeit gibt weitere zwanzig.

Brauche ich TypeScript?

Nein. Jedes Beispiel hier funktioniert genauso in reinem JavaScript. Der `Article`-Typ ist Dokumentation, keine Laufzeit-Anforderung. Die meisten Teams, die Next.js nutzen, nutzen schon TypeScript, deshalb gehen die Beispiele davon aus.

Kann ich Pages Router statt App Router nutzen?

Ja. Der Fetch-Helper bleibt identisch. Ersetze `app/blog/page.tsx` durch `pages/blog/index.tsx`, nutze `getStaticProps` für den Index und `getStaticParams` plus `getStaticProps` mit `revalidate: 60` für den Einzelpost. App Router wird für neue Projekte empfohlen, weil die ISR-Ergonomie sauberer ist.

Was ist mit RSS, Sitemap und Open Graph?

Kamaan generiert RSS automatisch unter `https://api.kamaan.io/v1/sites/{site_id}/rss`. Die Sitemap ist unter `/sites/{site_id}/sitemap.xml`. Beide aktualisieren sich, sobald du veröffentlichst. Für Open Graph setze Titel, Beschreibung und `featured_image_url` in den SEO-Feldern von Kamaan und lies sie in deiner Next.js-Funktion `generateMetadata`.

Wie zeige ich Entwürfe vorab?

Gib einen `Authorization: Bearer <token>`-Header beim fetch-Aufruf mit und füge `&status=draft` an die URL an. Die meisten Teams schützen das hinter einer `/blog/preview/[slug]`-Route mit einem geheimen Cookie. Kamaans API unterstützt Preview-Tokens direkt, sodass du keinen eigenen bauen musst.

Was, wenn ich später ein CMS wie Contentful oder Sanity hinzufügen will?

Nur der Fetch-Helper ändert sich. Tausche die API-URL und das JSON-Parsing, lasse die Seiten-Dateien gleich. Das ist der Wert davon, das CMS als JSON-Quelle statt als SDK-Abhängigkeit zu behandeln.

Funktioniert das mit React Server Components?

Ja. Jedes Beispiel oben ist eine Server Component. Keine `"use client"`-Direktive nötig, außer du fügst interaktive Widgets wie eine Suchleiste hinzu.

Kann ich das ohne Vercel betreiben?

Ja, mit Einschränkungen. Cloudflare Pages, Netlify, AWS Amplify und selbst gehostetes Node unterstützen Next.js. ISR funktioniert out of the box auf Vercel und Cloudflare. Auf Netlify braucht ISR deren On-Demand Builders. Selbst gehostet braucht den Standalone-Output-Modus.

Junaid Khalid
Written by
Junaid Khalid

Junaid Khalid is the founder of Kamaan, a headless blog CMS that auto-publishes in five languages and lets you manage every product blog from one dashboard.