Content layer for Markdown-driven websites.
Markdown from anywhere, served as a typed API:
get, list, navigation with a plugin ecosystem: schema validation, SQL queries, full-text search. No build step.content.ts
import { comarkContent } from 'comark-content'
import fs from 'comark-content/sources/fs'
export const content = comarkContent({
source: fs('./content'),
})
// parsed & typed version of content/hello.md
const page = await content.get('/hello')
// Generated navigation
const nav = await content.navigation()// Sources //
Bring your own source
Content can live next to your app for the fastest dev loop, in a separate repo so editors publish without a redeploy, or in any storage driver. Same API either way.
content.ts
import { comarkContent } from 'comark-content'
import fs from 'comark-content/sources/fs'
const content = comarkContent({
source: fs('./content'),
})
const page = await content.get('/getting-started')// Typed API //
Query it like a database
Types are generated from your actual frontmatter and narrow get, list, and query by source and by path. Add SQLite when you want SQL queries and full-text search.
const content = comarkContent({
source: fs('./content/posts'),
})
// Known path -> data auto-narrowed, no type parameter
const blogPost = await content.get('/posts/hello')
blogPost?.data.title // typed from your frontmatter
blogPost?.data.tags // autocompletes every field
const pages = await content.list()
// List all documents from all sources// Capabilities //
A small core. Everything else is a plugin.
Works with your stack
Nuxt, Next.js, Vite, SvelteKit, Nitro, Node, or Hono: mount one handler, render with Vue, React, or Svelte.
Documents and assets, together
Images and files live next to your Markdown: query them like content, serve them where they are referenced.
Type-safe from your frontmatter
Generated types narrow get() and query() by source and by path. One CLI command, or automatic with Vite.
// FAQ //
Common questions
An open source content layer for Markdown. It reads Markdown from the filesystem, GitHub, or any storage driver and exposes it through a typed API — get, list, navigation — with optional SQL queries and full-text search. It is a library, not a hosted service.
Those run at build time inside one framework, so every content change requires a rebuild. Comark Content parses content at runtime from any source and works with Nuxt, Next.js, Vite, Nitro, Node, or the browser. Push Markdown, it is live on the next request.
No. The core works with a source and an in-memory cache. Add SQLite (node or WASM) only when you want SQL queries over frontmatter or BM25 full-text search.
On the filesystem next to your app, in a GitHub repository, in any unstorage driver (S3, Cloudflare KV, Redis, HTTP), or behind a custom source you implement.
Any. The Content instance returns a framework-neutral AST rendered by Comark packages for Vue, React, Svelte, Angular, or plain HTML. A Nuxt module and a Vite plugin are available.
Yes. MIT-licensed open source. Your only costs are your own hosting and storage.
Add a content layer in five lines.
One source, one
get(). Add a database when you need queries and search, and write in Comark syntax when you need components.