ghost-headless-bloglisted
Install: claude install-skill kasuncfdo/ghost-headless-blog-skill
# Headless Ghost blog in Next.js (App Router)
Battle-tested patterns from a live production site (Next.js 16 / React 19 /
Tailwind v4, Ghost Content API v6.0). Everything below was learned the hard way — follow
the decisions, not just the code.
## Architecture at a glance
- **No `@tryghost/content-api` dependency.** Call the Content API REST endpoints directly
(`{GHOST_URL}/ghost/api/content/posts/?key=...`) with an `Accept-Version: v6.0` header.
The SDK adds weight and hides errors.
- **All Ghost fetching is server-side** (server components, route handlers,
`generateStaticParams`, sitemap). Content API keys only expose public data, but keep
them server-only anyway: env vars `GHOST_URL` / `GHOST_CONTENT_API_KEY` with **no
`NEXT_PUBLIC_` prefix**.
- **ISR everywhere + instant webhook purge.** Every blog route exports
`export const revalidate = 3600` and `export const dynamicParams = true`; a Ghost
Admin webhook hits `/api/revalidate?secret=...` on post publish/update/unpublish/delete
for instant purges. Hourly ISR is only the safety net.
- **Ghost post HTML is rendered verbatim** via `dangerouslySetInnerHTML` inside
`<article className="gh-content">`, styled by a dedicated `ghost-content.css`, with a
small HTML post-processing pass (blur-up images, LCP fix) and tiny client components
re-adding Ghost's interactive card JS (toggle cards).
## Routes to build
| Route | Purpose |
|---|---|
| `/blog` | Index: hero + feed. Only the Ghost-fetching part is an