@ghostwritr/next — overview
@ghostwritr/next is the server-side data client for the Next.js App Router. It pulls your published articles from the public static feed and hands you typed Article objects to render however you like.
It’s a pure data client — no React, no rendering, no styles. You bring the markup; render the Markdown body with <ArticleContent> from @ghostwritr/react, with react-markdown, with MDX, or with your own renderer.
Who it’s for
Section titled “Who it’s for”- You’re on Next 14+ with the App Router (
app/, server components,generateStaticParams,generateMetadata). - You want your articles to render as statically-generated pages — SSG, ISR, or dynamic SSR — your choice, one config flag.
- You want zero credentials in your app: reads are keyless. Your
siteIdis the read capability — there’s no API key.
The 30-second example
Section titled “The 30-second example”Install the SDK and the optional renderer:
npm install @ghostwritr/next @ghostwritr/react pnpm add @ghostwritr/next @ghostwritr/react yarn add @ghostwritr/next @ghostwritr/react bun add @ghostwritr/next @ghostwritr/react Create a server-only client as a module singleton, then read articles in any server component:
import "server-only";import { createGhostwritr } from "@ghostwritr/next/server";
export const gw = createGhostwritr({ siteId: process.env.GHOSTWRITR_SITE_ID!, // public read key — no API key revalidate: 3600, // ISR window in seconds (default 3600)});import { notFound } from "next/navigation";import { ArticleContent } from "@ghostwritr/react";import { gw } from "@/lib/ghostwritr";
export const generateStaticParams = gw.generateStaticParams;
export default async function Page({ params }: { params: Promise<{ slug: string }> }) { const article = await gw.getArticle((await params).slug); if (!article) notFound(); return ( <article> <h1>{article.title}</h1> <ArticleContent markdown={article.markdown} className="prose" /> </article> );}That’s a complete, statically-generated article page reading from the keyless feed. The client exposes exactly three methods:
gw.getArticles({ order? })— published articles, newest first by default.gw.getArticle(slug)— one article by slug, ornull.gw.generateStaticParams()—[{ slug }]for a[slug]route.
How reads work
Section titled “How reads work”Reads hit the public static feed at feeds.ghostwritr.io/{siteId}/ — immutable build snapshots, no auth. A missing feed (wrong or unseeded siteId) throws a GhostwritrError with code NOT_FOUND; the read fails closed rather than returning empty. See Keyless reads and The content feed for the contract.
Within a single render the feed is fetched once (Next’s built-in fetch memoization). Across requests, freshness is governed entirely by your rendering mode.
When to reach for it
Section titled “When to reach for it”- Use
@ghostwritr/nextwhen you’re on the App Router and want statically-generated pages with typed data and your own markup. - On plain Astro, prefer the
@ghostwritr/astroContent Layer loader. - On React Router v7, use
@ghostwritr/react-router. - Building your own integration? Drop to the framework-agnostic
@ghostwritr/feedcore.
What to reach for next
Section titled “What to reach for next”- Quickstart — a blog index and article pages with ISR, end to end.
- Rendering modes — ISR vs pure SSG vs dynamic SSR, and when to use each.
- Instant revalidation — wire the signed webhook so publishes go live in seconds.
- SEO metadata & sitemap — drive
generateMetadataandapp/sitemap.tsfrom the article fields. - API reference — every export, every field.