Blog
Publish blog posts with rich content, featured images, excerpts, and SEO metadata. Posts support multiple locales and are served via the public API with pagination.
How Blog Posts Work
Blog posts are created in the CMS dashboard with a rich content editor. Each post has a slug, title, excerpt, optional featuredImage, and author name.
The list endpoint returns posts without the full content body (just metadata and excerpt), making it efficient for index pages. Fetch a single post by slug to get the full content.
Fetching Blog Posts
List recent posts
const res = await fetch(
`${CMS_URL}/api/public/blog?limit=10`,
{ headers: { "x-api-key": CMS_API_KEY } }
);
const { posts, total, hasMore } = await res.json();const res = await fetch(
`${CMS_URL}/api/public/blog?limit=10`,
{ headers: { "x-api-key": CMS_API_KEY } }
);
const { posts, total, hasMore } = await res.json();Fetch a single post
const res = await fetch(
`${CMS_URL}/api/public/blog/${slug}`,
{ headers: { "x-api-key": CMS_API_KEY } }
);
const post = await res.json();
// post.content contains the full rich contentconst res = await fetch(
`${CMS_URL}/api/public/blog/${slug}`,
{ headers: { "x-api-key": CMS_API_KEY } }
);
const post = await res.json();
// post.content contains the full rich contentBuilding a Blog Index
Example: Blog listing page
async function BlogIndex() {
const res = await fetch(
`${process.env.CMS_URL}/api/public/blog?limit=10`,
{
headers: { "x-api-key": process.env.CMS_API_KEY! },
next: { revalidate: 60 },
}
);
const { posts, hasMore } = await res.json();
return (
<div>
{posts.map((post) => (
<article key={post.slug}>
{post.featuredImage && (
<img src={post.featuredImage} alt={post.title} />
)}
<h2><a href={`/blog/${post.slug}`}>{post.title}</a></h2>
<p>{post.excerpt}</p>
<span>{post.author}</span>
</article>
))}
{hasMore && <a href="/blog?page=2">Load more</a>}
</div>
);
}async function BlogIndex() {
const res = await fetch(
`${process.env.CMS_URL}/api/public/blog?limit=10`,
{
headers: { "x-api-key": process.env.CMS_API_KEY! },
next: { revalidate: 60 },
}
);
const { posts, hasMore } = await res.json();
return (
<div>
{posts.map((post) => (
<article key={post.slug}>
{post.featuredImage && (
<img src={post.featuredImage} alt={post.title} />
)}
<h2><a href={`/blog/${post.slug}`}>{post.title}</a></h2>
<p>{post.excerpt}</p>
<span>{post.author}</span>
</article>
))}
{hasMore && <a href="/blog?page=2">Load more</a>}
</div>
);
}