Next.js

Set up Comark Content in a Next.js app.

With the App Router, server components read the Content instance in-process: no route, no client, just await content.get(). The handler and browser client only come in when client components need to fetch content.

Install the packages

pnpm add comark-content @comark/react server-only

Create the Content instance

Mark the module server-only so the parser and your content never leak into a client bundle:

src/lib/content.ts
import 'server-only'
import { comarkContent } from 'comark-content'
import fs from 'comark-content/sources/fs'

export const content = comarkContent({
  source: fs('./content'),
})

Render a page from a server component

Server components call the Content instance directly, no HTTP round-trip involved:

src/app/page.tsx
import { MarkdownDocument } from '@comark/react'
import { notFound } from 'next/navigation'
import { content } from '@/lib/content'

export default async function Page() {
  const page = await content.get('/')
  if (!page) notFound()

  return <MarkdownDocument value={page} />
}

Map Markdown components to your own React components through the components prop, see the React renderer.

Optional: expose the handler for client components

If client components need to read content, mount content.handler() on a route handler — it already speaks web-standard Request/Response:

src/app/api/content/[...path]/route.ts
import { content } from '@/lib/content'

export const GET = (request: Request) => content.handler(request)

Then consume it with the browser client, same read API as the server instance:

src/lib/content-client.ts
import { createContentClient } from 'comark-content/client'

export const contentClient = createContentClient()
// contentClient.get('/'), contentClient.list(), contentClient.navigation()

Generate source types

Type content.get() from your frontmatter by generating source types:

Terminal
npx comark-content prepare

Add comark-content.d.ts to your tsconfig.json include, see Type Safety. As well as your .gitignore.

In development you can call content.watch() from src/lib/content.ts so content edits invalidate the manifest without restarting the dev server, the Next example shows the Turbopack-safe wiring.

Going further

Next.js example

The full runnable app: YAML, JSON, Markdown, and json-render pages with HeroUI.

Client & handler

How the handler/client pair works, and how to extend it with plugin pairs.