Claude-skill-registry content-collections
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/content-collections-jackspace-claudeskillz" ~/.claude/skills/majiayu000-claude-skill-registry-content-collections && rm -rf "$T"
skills/data/content-collections-jackspace-claudeskillz/SKILL.mdContent Collections
Status: 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
What is Content Collections?
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:
- Define collections in
(name, directory, Zod schema)content-collections.ts - CLI/plugin scans filesystem, parses frontmatter, validates against schema
- Generates TypeScript modules in
.content-collections/generated/ - Import collections:
import { allPosts } from "content-collections"
Perfect for: Blogs, documentation sites, content-heavy apps with Cloudflare Workers, Vite, Next.js.
Quick Start (5 Minutes)
1. Install Dependencies
pnpm add -D @content-collections/core @content-collections/vite zod
2. Configure TypeScript Path Alias
Add to
tsconfig.json:
{ "compilerOptions": { "paths": { "content-collections": ["./.content-collections/generated"] } } }
- Configure Vite Plugin
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() ], });
4. Update .gitignore
.content-collections/
5. Create Collection Config
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], });
6. Create Content Directory
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...
7. Import and Use
import { allPosts } from "content-collections"; console.log(allPosts); // Fully typed!
Result: Type-safe content with autocomplete, validation, and HMR.
Critical Rules
✅ Always Do:
- Add path alias to tsconfig.json - Required for imports to work
- Add .content-collections to .gitignore - Generated files shouldn't be committed
- Use Standard Schema validators - Zod, Valibot, ArkType supported
- Include
field in schema - Required for frontmatter parsingcontent - Await compileMDX in transforms - MDX compilation is async
- Put contentCollections() after react() in Vite - Plugin order matters
❌ Never Do:
- Commit .content-collections directory - Always generated, never committed
- Use non-standard validators - Must support StandardSchema spec
- Forget to restart dev server after config changes - Required for new collections
- Use sync transforms with async operations - Transform must be async
- Double-wrap path alias - Use
notcontent-collections./content-collections - Import from wrong package -
for config,@content-collections/core
for datacontent-collections
Known Issues Prevention
Issue #1: Module not found: 'content-collections'
Error:
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
Issue #2: Vite Constant Restart Loop
Error: Dev server continuously restarts, infinite loop.
Why it happens: Vite watching
.content-collections directory changes, which triggers regeneration.
Prevention:
- Add to
:.gitignore
.content-collections/
- Add to
(if still happening):vite.config.ts
export default defineConfig({ server: { watch: { ignored: ["**/.content-collections/**"], }, }, });
Source: GitHub Issue #591 (TanStack Start)
Issue #3: Transform Types Not Reflected
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
Issue #4: Collection Not Updating on File Change
Error: New content files not appearing in collection.
Why it happens: Glob pattern doesn't match, or dev server needs restart.
Prevention:
- Verify glob pattern matches your files:
include: "*.md" // Only root files include: "**/*.md" // All nested files include: "posts/*.md" // Only posts/ folder
- Restart dev server after adding new files outside watched patterns
- Check file actually saved (watch for editor issues)
Source: Common user error
Issue #5: MDX Type Errors with Shiki
Error:
esbuild errors with shiki langAlias or compilation failures.
Why it happens: Version incompatibility between Shiki and Content Collections.
Prevention:
Use compatible versions:
{ "devDependencies": { "@content-collections/mdx": "^0.2.2", "shiki": "^1.0.0" } }
Check official compatibility matrix in docs before upgrading Shiki.
Source: GitHub Issue #598 (Next.js 15)
Issue #6: Custom Path Aliases in MDX Imports Fail
Error: MDX imports with
@ alias don't resolve.
Why it happens: MDX compiler doesn't respect tsconfig path aliases.
Prevention:
Use relative paths in MDX imports:
<!-- ❌ Won't work --> import Component from "@/components/Component" <!-- ✅ Works --> import Component from "../../components/Component"
Or configure files appender (advanced, see references/transform-cookbook.md).
Source: GitHub Issue #547
Issue #7: Unclear Validation Error Messages
Error: Cryptic Zod validation errors like "Expected string, received undefined".
Why it happens: Zod errors aren't formatted for content context.
Prevention:
Add custom error messages to schema:
schema: z.object({ title: z.string({ required_error: "Title is required in frontmatter", invalid_type_error: "Title must be a string", }), date: z.string().refine( (val) => !isNaN(Date.parse(val)), "Date must be valid ISO date (YYYY-MM-DD)" ), })
Source: GitHub Issue #403
Issue #8: Ctrl+C Doesn't Stop Process
Error: Dev process hangs on exit, requires
kill -9.
Why it happens: File watcher not cleaning up properly.
Prevention:
This is a known issue with the watcher. Workarounds:
- Use
when it hangskill -9 <pid> - Use
separately (not plugin) for more controlcontent-collections watch - Add cleanup handler in
(advanced)vite.config.ts
Source: GitHub Issue #546
Configuration Patterns
Basic Blog Collection
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(), tags: z.array(z.string()).optional(), content: z.string(), }), }); export default defineConfig({ collections: [posts], });
Multi-Collection Setup
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(), }), }); const docs = defineCollection({ name: "docs", directory: "content/docs", include: "**/*.md", // Nested folders schema: z.object({ title: z.string(), category: z.string(), order: z.number().optional(), content: z.string(), }), }); export default defineConfig({ collections: [posts, docs], });
Transform Functions (Computed Fields)
const posts = defineCollection({ name: "posts", directory: "content/posts", include: "*.md", schema: z.object({ title: z.string(), date: z.string(), content: z.string(), }), transform: (post) => ({ ...post, slug: post._meta.path.replace(/\.md$/, ""), readingTime: Math.ceil(post.content.split(/\s+/).length / 200), year: new Date(post.date).getFullYear(), }), });
MDX with React Components
import { compileMDX } from "@content-collections/mdx"; const posts = defineCollection({ name: "posts", directory: "content/posts", include: "*.mdx", schema: z.object({ title: z.string(), date: z.string(), content: z.string(), }), transform: async (post) => { const mdx = await compileMDX(post.content, { syntaxHighlighter: "shiki", shikiOptions: { theme: "github-dark", }, }); return { ...post, mdx, slug: post._meta.path.replace(/\.mdx$/, ""), }; }, });
React Component Integration
Using Collections in React
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> ); }
Rendering MDX Content
import { MDXContent } from "@content-collections/mdx/react"; export function BlogPost({ post }: { post: { mdx: string } }) { return ( <article> <MDXContent code={post.mdx} /> </article> ); }
Cloudflare Workers Deployment
Content Collections is perfect for Cloudflare Workers because:
- Build-time only (no runtime filesystem access)
- Outputs static JavaScript modules
- No Node.js dependencies in generated code
Deployment Pattern
Local Dev → content-collections build → vite build → wrangler deploy
wrangler.toml
name = "my-content-site" compatibility_date = "2025-11-07" [assets] directory = "./dist" binding = "ASSETS"
Build Script
package.json:
{ "scripts": { "dev": "vite", "build": "vite build", "deploy": "pnpm build && wrangler deploy" } }
Note: Vite plugin handles
content-collections build automatically!
Using Bundled Resources
Templates (templates/)
Copy-paste ready configuration files:
- Basic blog setupcontent-collections.ts
- Multiple collectionscontent-collections-multi.ts
- MDX with syntax highlightingcontent-collections-mdx.ts
- Complete TypeScript configtsconfig.json
- Vite plugin setupvite.config.ts
- Example content fileblog-post.md
- React list componentBlogList.tsx
- React MDX render componentBlogPost.tsx
- Cloudflare Workers configwrangler.toml
References (references/)
Deep-dive documentation for advanced topics:
- Common Zod schema patternsschema-patterns.md
- Transform function recipestransform-cookbook.md
- MDX + React integrationmdx-components.md
- Cloudflare Workers setupdeployment-guide.md
When to load: Claude should load these when you need advanced patterns beyond basic setup.
Scripts (scripts/)
- One-command automated setupinit-content-collections.sh
Dependencies
Required
{ "devDependencies": { "@content-collections/core": "^0.12.0", "@content-collections/vite": "^0.2.7", "zod": "^3.23.8" } }
Optional (MDX)
{ "devDependencies": { "@content-collections/markdown": "^0.1.4", "@content-collections/mdx": "^0.2.2", "shiki": "^1.0.0" } }
Official Documentation
- Official Site: https://www.content-collections.dev
- Documentation: https://www.content-collections.dev/docs
- GitHub: https://github.com/sdorra/content-collections
- Vite Plugin: https://www.content-collections.dev/docs/vite
- MDX Integration: https://www.content-collections.dev/docs/mdx
Package Versions (Verified 2025-11-07)
| 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 |
Troubleshooting
Problem: TypeScript can't find 'content-collections'
Solution: Add path alias to
tsconfig.json, restart TS server.
Problem: Vite keeps restarting
Solution: Add
.content-collections/ to .gitignore and Vite watch ignore.
Problem: Changes not reflecting
Solution: Restart dev server, verify glob pattern, check file saved.
Problem: MDX compilation errors
Solution: Check Shiki version compatibility, verify MDX syntax.
Problem: Validation errors unclear
Solution: Add custom error messages to Zod schema.
Complete Setup Checklist
- Installed
and@content-collections/core@content-collections/vite - Installed
for schema validationzod - Added path alias to
tsconfig.json - Added
tocontentCollections()
(after react())vite.config.ts - Added
to.content-collections/.gitignore - Created
in project rootcontent-collections.ts - Created content directory (e.g.,
)content/posts/ - Defined collection with Zod schema
- Created first content file with frontmatter
- Imported collection in React component
- Verified types work (autocomplete)
- Tested hot reloading (change content file)
Questions? Issues?
- Check
directory for deep divesreferences/ - Verify path alias in tsconfig.json
- Check Vite plugin order (after react())
- Review known issues above
- Check official docs: https://www.content-collections.dev/docs