**Status**: Production Ready ✅
Generates type-safe TypeScript data from Markdown/MDX files with automatic validation.
npx claudepluginhub secondsky/claude-skillsThis skill inherits all available tools. When active, it can use any tool Claude has access to.
assets/example-template.txtreferences/advanced-troubleshooting.mdreferences/deployment-guide.mdreferences/mdx-components.mdreferences/schema-patterns.mdreferences/transform-cookbook.mdscripts/example-script.shscripts/init-content-collections.shtemplates/BlogList.tsxtemplates/BlogPost.tsxtemplates/blog-post.mdtemplates/content-collections-mdx.tstemplates/content-collections-multi.tstemplates/content-collections.tstemplates/tsconfig.jsontemplates/vite.config.tstemplates/wrangler.tomlStatus: Production Ready ✅ Last Updated: 2025-11-07 Dependencies: None Latest Versions: @content-collections/core@0.12.0, @content-collections/vite@0.2.7, zod@3.23.8
Content Collections transforms local content files (Markdown/MDX) into type-safe TypeScript data with automatic validation at build time.
Problem it solves: Manual content parsing, lack of type safety, runtime errors from invalid frontmatter.
How it works:
content-collections.ts (name, directory, Zod schema).content-collections/generated/import { allPosts } from "content-collections"Perfect for: Blogs, documentation sites, content-heavy apps with Cloudflare Workers, Vite, Next.js.
# Bun (recommended)
bun add -d @content-collections/core @content-collections/vite zod
# npm
npm install -D @content-collections/core @content-collections/vite zod
# pnpm
pnpm add -D @content-collections/core @content-collections/vite zod
Add to tsconfig.json:
{
"compilerOptions": {
"paths": {
"content-collections": ["./.content-collections/generated"]
}
}
}
Add to vite.config.ts:
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import contentCollections from "@content-collections/vite";
export default defineConfig({
plugins: [
react(),
contentCollections(), // MUST come after react()
],
});
.content-collections/
Create content-collections.ts in project root:
import { defineCollection, defineConfig } from "@content-collections/core";
import { z } from "zod";
const posts = defineCollection({
name: "posts",
directory: "content/posts",
include: "*.md",
schema: z.object({
title: z.string(),
date: z.string(),
description: z.string(),
content: z.string(),
}),
});
export default defineConfig({
collections: [posts],
});
mkdir -p content/posts
Create content/posts/first-post.md:
---
title: My First Post
date: 2025-11-07
description: Introduction to Content Collections
---
# My First Post
Content goes here...
import { allPosts } from "content-collections";
console.log(allPosts); // Fully typed!
Result: Type-safe content with autocomplete, validation, and HMR.
content field in schema - Required for frontmatter parsingcontent-collections not ./content-collections@content-collections/core for config, content-collections for dataError: Cannot find module 'content-collections' or its corresponding type declarations
Why it happens: Missing TypeScript path alias configuration.
Prevention:
Add to tsconfig.json:
{
"compilerOptions": {
"paths": {
"content-collections": ["./.content-collections/generated"]
}
}
}
Restart TypeScript server in VS Code: Cmd+Shift+P → "TypeScript: Restart TS Server"
Source: Common user error
Error: Dev server continuously restarts, infinite loop.
Why it happens: Vite watching .content-collections directory changes, which triggers regeneration.
Prevention:
.gitignore:.content-collections/
vite.config.ts (if still happening):export default defineConfig({
server: {
watch: {
ignored: ["**/.content-collections/**"],
},
},
});
Source: GitHub Issue #591 (TanStack Start)
Error: TypeScript types don't match transformed documents.
Why it happens: TypeScript doesn't automatically infer transform function return type.
Prevention:
Explicitly type your transform return:
const posts = defineCollection({
name: "posts",
// ... schema
transform: (post): PostWithSlug => ({ // Type the return!
...post,
slug: post._meta.path.replace(/\.md$/, ""),
}),
});
type PostWithSlug = {
// ... schema fields
slug: string;
};
Source: GitHub Issue #396
Additional issues covered in references/advanced-troubleshooting.md:
| Issue | Error | Quick Fix |
|---|---|---|
| #4 | Collection not updating | Verify glob pattern, restart dev server |
| #5 | MDX/Shiki errors | Use compatible versions (shiki ^1.0.0) |
| #6 | MDX path aliases fail | Use relative paths in MDX imports |
| #7 | Unclear validation errors | Add custom Zod error messages |
| #8 | Ctrl+C doesn't stop | Use kill -9 or separate watch command |
| Pattern | Use Case | Template |
|---|---|---|
| Basic Blog | Single collection, Markdown only | templates/content-collections.ts |
| Multi-Collection | Posts + Docs, nested folders | templates/content-collections-multi.ts |
| Transform Functions | Computed fields (slug, readingTime) | See references/transform-cookbook.md |
| MDX + React | Syntax highlighting, React components | templates/content-collections-mdx.ts |
For detailed schema patterns (dates, tags, validation), load references/schema-patterns.md.
import { allPosts } from "content-collections";
export function BlogList() {
return (
<ul>
{allPosts.map((post) => (
<li key={post._meta.path}>
<h2>{post.title}</h2>
<p>{post.description}</p>
<time>{post.date}</time>
</li>
))}
</ul>
);
}
import { MDXContent } from "@content-collections/mdx/react";
export function BlogPost({ post }: { post: { mdx: string } }) {
return (
<article>
<MDXContent code={post.mdx} />
</article>
);
}
Content Collections is perfect for Cloudflare Workers (build-time only, no runtime filesystem). Use template templates/wrangler.toml for config.
Pattern: vite build → wrangler deploy (Vite plugin handles content-collections automatically)
For detailed deployment guide, load references/deployment-guide.md.
content-collections.ts, content-collections-multi.ts, content-collections-mdx.ts, tsconfig.json, vite.config.ts, BlogList.tsx, BlogPost.tsx, blog-post.md, wrangler.toml
init-content-collections.sh - One-command automated setup
{
"devDependencies": {
"@content-collections/core": "^0.12.0",
"@content-collections/vite": "^0.2.7",
"zod": "^3.23.8"
}
}
{
"devDependencies": {
"@content-collections/markdown": "^0.1.4",
"@content-collections/mdx": "^0.2.2",
"shiki": "^1.0.0"
}
}
| Package | Version | Status |
|---|---|---|
| @content-collections/core | 0.12.0 | ✅ Latest stable |
| @content-collections/vite | 0.2.7 | ✅ Latest stable |
| @content-collections/mdx | 0.2.2 | ✅ Latest stable |
| @content-collections/markdown | 0.1.4 | ✅ Latest stable |
| zod | 3.23.8 | ✅ Latest stable |
| Problem | Solution |
|---|---|
| TypeScript can't find module | Add path alias to tsconfig.json, restart TS server |
| Vite keeps restarting | Add .content-collections/ to .gitignore |
| Changes not reflecting | Restart dev server, verify glob pattern |
| MDX compilation errors | Check Shiki version compatibility |
| Validation errors unclear | Add custom Zod error messages |
| Reference | Load When... |
|---|---|
schema-patterns.md | Setting up complex schemas, date validation, optional fields |
transform-cookbook.md | Adding computed fields, async transforms, slugs |
mdx-components.md | Integrating React components in MDX, syntax highlighting |
deployment-guide.md | Deploying to Cloudflare Workers or other platforms |
advanced-troubleshooting.md | Issues #4-8 (file watching, path aliases, process hanging) |
@content-collections/core and @content-collections/vitezod for schema validationtsconfig.jsoncontentCollections() to vite.config.ts (after react()).content-collections/ to .gitignorecontent-collections.ts in project rootcontent/posts/)This skill should be used when the user asks about libraries, frameworks, API references, or needs code examples. Activates for setup questions, code generation involving libraries, or mentions of specific frameworks like React, Vue, Next.js, Prisma, Supabase, etc.