.agents/skills/content-collections/SKILL.md
Production-tested setup for Content Collections - a TypeScript-first build tool that transforms local content files (Markdown/MDX) into type-safe data collections with automatic validation. Use when: building blogs, documentation sites, or content-heavy applications with Vite + React, setting up MDX content with React components, implementing type-safe content schemas with Zod, migrating from Contentlayer, or encountering TypeScript import errors with content collections. Covers: Vite plugin setup, tsconfig path aliases, collection schemas with Zod validation, MDX compilation with compileMDX, transform functions for computed properties, rehype/remark plugins, React component integration with MDXContent, Cloudflare Workers deployment, and production build optimization. Keywords: content-collections, @content-collections/core, @content-collections/vite, @content-collections/mdx, MDX, markdown, Zod schema validation, type-safe content, frontmatter, compileMDX, defineCollection, defineConfig, Vite plugin, tsconfig paths, .content-collections/generated, MDXContent component, rehype plugins, remark plugins, content schema, document transform, allPosts import, static site generation, blog setup, documentation, Cloudflare Workers static assets, content validation errors, module not found content-collections, path alias not working, MDX type errors, transform function async, collection not updating
npx skillsauth add em-jones/staccato-toolkit content-collectionsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Status: Production Ready ✅ Last Updated: 2025-11-07 Dependencies: None Latest Versions: @content-collections/[email protected], @content-collections/[email protected], [email protected]
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.
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
Error: New content files not appearing in collection.
Why it happens: Glob pattern doesn't match, or dev server needs restart.
Prevention:
include: "*.md" // Only root files
include: "**/*.md" // All nested files
include: "posts/*.md" // Only posts/ folder
Source: Common user error
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)
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
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
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:
kill -9 <pid> when it hangscontent-collections watch separately (not plugin) for more controlvite.config.ts (advanced)Source: GitHub Issue #546
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],
});
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],
});
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(),
}),
});
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$/, ""),
};
},
});
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 because:
Local Dev → content-collections build → vite build → wrangler deploy
name = "my-content-site"
compatibility_date = "2025-11-07"
[assets]
directory = "./dist"
binding = "ASSETS"
package.json:
{
"scripts": {
"dev": "vite",
"build": "vite build",
"deploy": "pnpm build && wrangler deploy"
}
}
Note: Vite plugin handles content-collections build automatically!
Copy-paste ready configuration files:
content-collections.ts - Basic blog setupcontent-collections-multi.ts - Multiple collectionscontent-collections-mdx.ts - MDX with syntax highlightingtsconfig.json - Complete TypeScript configvite.config.ts - Vite plugin setupblog-post.md - Example content fileBlogList.tsx - React list componentBlogPost.tsx - React MDX render componentwrangler.toml - Cloudflare Workers configDeep-dive documentation for advanced topics:
schema-patterns.md - Common Zod schema patternstransform-cookbook.md - Transform function recipesmdx-components.md - MDX + React integrationdeployment-guide.md - Cloudflare Workers setupWhen to load: Claude should load these when you need advanced patterns beyond basic setup.
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 |
Solution: Add path alias to tsconfig.json, restart TS server.
Solution: Add .content-collections/ to .gitignore and Vite watch ignore.
Solution: Restart dev server, verify glob pattern, check file saved.
Solution: Check Shiki version compatibility, verify MDX syntax.
Solution: Add custom error messages to Zod schema.
@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/)Questions? Issues?
references/ directory for deep divestools
<!--VITE PLUS START--> # Using Vite+, the Unified Toolchain for the Web This project is using Vite+, a unified toolchain built on top of Vite, Rolldown, Vitest, tsdown, Oxlint, Oxfmt, and Vite Task. Vite+ wraps runtime management, package management, and frontend tooling in a single global CLI called `vp`. Vite+ is distinct from Vite, but it invokes Vite through `vp dev` and `vp build`. ## Vite+ Workflow `vp` is a global binary that handles the full development lifecycle. Run `vp help` to pr
development
Guide for building performant data tables. Uses tanstack-table for table logic (sorting, filtering, pagination) and tanstack-virtual for rendering large datasets efficiently.
development
Expert guidance for building observable, expressive, and fault-tolerant TypeScript applications using the effect-ts/effect ecosystem. Covers Effect<A, E, R> type, error management, dependency injection via Layers, observability (logging, metrics, tracing), concurrency with Fibers, retry/scheduling, Schema validation, Streams, and Sinks.
tools
Complete E2E (end-to-end) and integration testing skill for TypeScript/NestJS projects using Jest, real infrastructure via Docker, and GWT pattern. ALWAYS use this skill when user needs to: **SETUP** - Initialize or configure E2E testing infrastructure: - Set up E2E testing for a new project - Configure docker-compose for testing (Kafka, PostgreSQL, MongoDB, Redis) - Create jest-e2e.config.ts or E2E Jest configuration - Set up test helpers for database, Kafka, or Redis - Configure .env.e2e environment variables - Create test/e2e directory structure **WRITE** - Create or add E2E/integration tests: - Write, create, add, or generate e2e tests or integration tests - Test API endpoints, workflows, or complete features end-to-end - Test with real databases, message brokers, or external services - Test Kafka consumers/producers, event-driven workflows - Working on any file ending in .e2e-spec.ts or in test/e2e/ directory - Use GWT (Given-When-Then) pattern for tests **REVIEW** - Audit or evaluate E2E tests: - Review existing E2E tests for quality - Check test isolation and cleanup patterns - Audit GWT pattern compliance - Evaluate assertion quality and specificity - Check for anti-patterns (multiple WHEN actions, conditional assertions) **RUN** - Execute or analyze E2E test results: - Run E2E tests - Start/stop Docker infrastructure for testing - Analyze E2E test results - Verify Docker services are healthy - Interpret test output and failures **DEBUG** - Fix failing or flaky E2E tests: - Fix failing E2E tests - Debug flaky tests or test isolation issues - Troubleshoot connection errors (database, Kafka, Redis) - Fix timeout issues or async operation failures - Diagnose race conditions or state leakage - Debug Kafka message consumption issues **OPTIMIZE** - Improve E2E test performance: - Speed up slow E2E tests - Optimize Docker infrastructure startup - Replace fixed waits with smart polling - Reduce beforeEach cleanup time - Improve test parallelization where safe Keywords: e2e, end-to-end, integration test, e2e-spec.ts, test/e2e, Jest, supertest, NestJS, Kafka, Redpanda, PostgreSQL, MongoDB, Redis, docker-compose, GWT pattern, Given-When-Then, real infrastructure, test isolation, flaky test, MSW, nock, waitForMessages, fix e2e, debug e2e, run e2e, review e2e, optimize e2e, setup e2e