Contentful CMS Implementation with Claude Code
Learn about Contentful CMS implementation using Claude Code. Practical tips and code examples included.
Streamlining Contentful CMS Integration With Claude Code
Contentful is the flagship of headless CMS platforms, enabling API-first content management. With structured content models and a rich delivery API, you can fetch content from any frontend. With Claude Code, you can efficiently go from content model design to frontend integration.
Designing the Content Model
> Design a content model for a blog site in Contentful.
> Use three content types: article, category, and author.
// scripts/setup-content-model.ts
import contentful from 'contentful-management';
const client = contentful.createClient({
accessToken: process.env.CONTENTFUL_MANAGEMENT_TOKEN!,
});
async function setupContentModel() {
const space = await client.getSpace(process.env.CONTENTFUL_SPACE_ID!);
const env = await space.getEnvironment('master');
// Author content type
const author = await env.createContentTypeWithId('author', {
name: 'Author',
fields: [
{ id: 'name', name: 'Name', type: 'Symbol', required: true },
{ id: 'slug', name: 'Slug', type: 'Symbol', required: true },
{ id: 'bio', name: 'Bio', type: 'Text' },
{ id: 'avatar', name: 'Avatar', type: 'Link', linkType: 'Asset' },
],
});
await author.publish();
// Category
const category = await env.createContentTypeWithId('category', {
name: 'Category',
fields: [
{ id: 'name', name: 'Name', type: 'Symbol', required: true },
{ id: 'slug', name: 'Slug', type: 'Symbol', required: true },
{ id: 'description', name: 'Description', type: 'Text' },
],
});
await category.publish();
// Blog post
const blogPost = await env.createContentTypeWithId('blogPost', {
name: 'Blog Post',
fields: [
{ id: 'title', name: 'Title', type: 'Symbol', required: true },
{ id: 'slug', name: 'Slug', type: 'Symbol', required: true },
{ id: 'excerpt', name: 'Excerpt', type: 'Text' },
{ id: 'body', name: 'Body', type: 'RichText' },
{ id: 'featuredImage', name: 'Featured Image', type: 'Link', linkType: 'Asset' },
{ id: 'author', name: 'Author', type: 'Link', linkType: 'Entry' },
{ id: 'category', name: 'Category', type: 'Link', linkType: 'Entry' },
{ id: 'tags', name: 'Tags', type: 'Array', items: { type: 'Symbol' } },
{ id: 'publishedAt', name: 'Published At', type: 'Date' },
],
});
await blogPost.publish();
}
Fetching Content
> Create a client that fetches blog posts via Contentful's Content Delivery API.
> Also generate TypeScript types.
// src/lib/contentful.ts
import { createClient, type Entry, type Asset } from 'contentful';
const client = createClient({
space: process.env.CONTENTFUL_SPACE_ID!,
accessToken: process.env.CONTENTFUL_ACCESS_TOKEN!,
});
// Preview client
const previewClient = createClient({
space: process.env.CONTENTFUL_SPACE_ID!,
accessToken: process.env.CONTENTFUL_PREVIEW_TOKEN!,
host: 'preview.contentful.com',
});
function getClient(preview = false) {
return preview ? previewClient : client;
}
// Type definitions
interface BlogPostFields {
title: string;
slug: string;
excerpt: string;
body: any; // Rich Text Document
featuredImage: Asset;
author: Entry<AuthorFields>;
category: Entry<CategoryFields>;
tags: string[];
publishedAt: string;
}
interface AuthorFields {
name: string;
slug: string;
bio: string;
avatar: Asset;
}
interface CategoryFields {
name: string;
slug: string;
description: string;
}
// Get the list of posts
export async function getBlogPosts(options?: {
limit?: number;
skip?: number;
category?: string;
preview?: boolean;
}) {
const { limit = 10, skip = 0, category, preview = false } = options || {};
const query: any = {
content_type: 'blogPost',
order: ['-fields.publishedAt'],
limit,
skip,
include: 2,
};
if (category) {
query['fields.category.sys.contentType.sys.id'] = 'category';
query['fields.category.fields.slug'] = category;
}
const entries = await getClient(preview).getEntries<BlogPostFields>(query);
return {
posts: entries.items,
total: entries.total,
};
}
// Get a single post
export async function getBlogPost(slug: string, preview = false) {
const entries = await getClient(preview).getEntries<BlogPostFields>({
content_type: 'blogPost',
'fields.slug': slug,
include: 2,
limit: 1,
});
return entries.items[0] || null;
}
ISR Implementation in Next.js
// app/blog/[slug]/page.tsx
import { getBlogPost, getBlogPosts } from '@/lib/contentful';
import { documentToReactComponents } from '@contentful/rich-text-react-renderer';
import { notFound } from 'next/navigation';
export const revalidate = 60; // revalidate every 60 seconds
export async function generateStaticParams() {
const { posts } = await getBlogPosts({ limit: 100 });
return posts.map((post) => ({ slug: post.fields.slug }));
}
export default async function BlogPostPage({
params,
}: {
params: { slug: string };
}) {
const post = await getBlogPost(params.slug);
if (!post) notFound();
return (
<article className="max-w-3xl mx-auto p-6">
<h1 className="text-4xl font-bold">{post.fields.title}</h1>
<p className="text-gray-500 mt-2">
{new Date(post.fields.publishedAt).toLocaleDateString('en-US')}
</p>
<div className="prose mt-8">
{documentToReactComponents(post.fields.body)}
</div>
</article>
);
}
Summary
Combining Contentful’s API-first approach with Claude Code lets you efficiently build a flexible content management system. See the blog CMS build guide and SSR/SSG comparison for related topics.
For more on Contentful, see the official Contentful documentation.
Level up your Claude Code workflow
50 battle-tested prompt templates you can copy-paste into Claude Code right now.
Free PDF: Claude Code Cheatsheet in 5 Minutes
Key commands, shortcuts, and prompt examples on a single printable page.
About the Author
Masa
Engineer obsessed with Claude Code. Runs claudecode-lab.com, a 10-language tech media with 2,000+ pages.
Related Posts
How to Supercharge Your Side Projects with Claude Code [With Examples]
How to Supercharge Your Side Projects with Claude Code [With Examples]. A practical guide with code examples.
How to Automate Refactoring with Claude Code
Learn how to automate refactoring using Claude Code. Includes practical code examples and step-by-step guidance.
Complete CORS Configuration Guide with Claude Code
A complete CORS configuration guide using Claude Code. Practical tips and code examples included.