Getting started
@next-md-blog/core is organized around collections (the collection API, introduced in v1.2). A collection owns one content surface (blog, glossary, docs, changelog, …) with its own folder, URL segment, schema type, and RSS feed. A single shared SiteConfig holds site-wide concerns (name, URL, Organization JSON-LD).
Install
npm install @next-md-blog/core
# (CLI for scaffolding routes and SEO files)
npx @next-md-blog/cliDefine your site + collections
next-md-blog.config.ts
import { defineSite, defineCollection } from '@next-md-blog/core';
export const site = defineSite({
siteName: 'Acme',
siteUrl: process.env.NEXT_PUBLIC_SITE_URL ?? 'https://acme.example',
defaultAuthor: 'Acme Team',
defaultLang: 'en',
});
// One collection per content surface. Coexist freely.
export const blog = defineCollection({
id: 'blog',
contentDir: 'content/blog',
pathSegment: 'blog', // → /[lang]/blog/[slug]
site,
});
export const glossary = defineCollection({
id: 'glossary',
contentDir: 'content/glossary',
pathSegment: 'glossary',
schemaType: 'DefinedTerm', // built-in glossary schema
rss: false,
site,
});Write a post
content/blog/welcome.md
---
title: Welcome
description: First post.
date: 2026-01-01
tags: [intro]
---
Hello world.Render it (App Router)
app/blog/[slug]/page.tsx
import { notFound } from 'next/navigation';
import { MarkdownContent } from '@next-md-blog/core';
import { blog } from '@/next-md-blog.config';
export async function generateStaticParams() {
const posts = await blog.getAll();
return posts.map((post) => ({ slug: post.slug }));
}
export async function generateMetadata({ params }: { params: Promise<{ slug: string }> }) {
const { slug } = await params;
const post = await blog.getOne(slug);
if (!post) return { title: 'Not found' };
return blog.metadata(post);
}
export default async function Page({ params }: { params: Promise<{ slug: string }> }) {
const { slug } = await params;
const post = await blog.getOne(slug);
if (!post) notFound();
return <MarkdownContent content={post.content} />;
}That’s the minimum. The collection encapsulates contentDir, config, locale handling, and schema generation — no more threading options through every call site.
Site-wide files (app/sitemap.ts, robots.ts, feed.xml)
app/sitemap.ts
import { composeSitemap } from '@next-md-blog/core';
import { blog, glossary, site } from '@/next-md-blog.config';
const LOCALES = [site.defaultLang ?? 'en'] as const;
export default async function sitemap() {
return composeSitemap({
collections: [blog, glossary],
locales: LOCALES,
});
}app/robots.ts
import { getRobots } from '@next-md-blog/core/next';
import { site } from '@/next-md-blog.config';
export default () => getRobots(site);app/feed.xml/route.ts
import { blog } from '@/next-md-blog.config';
export async function GET() {
return blog.rssResponse();
}Next steps
- Configuration — every
defineSiteanddefineCollectionfield. - Content & frontmatter — what frontmatter fields the library understands.
- SEO & feeds — metadata helpers, JSON-LD graph, sitemap composition, llms.txt.
- Internationalization — per-locale collections and hreflang.
- CLI — what
npx @next-md-blog/cliscaffolds.
Last updated on