Imagine: your editor updates a content type, and the frontend starts throwing errors — undefined fields, wrong dates, broken builds. Without typings, every change to the content model becomes a disaster. And if you also need to update images and Rich Text, publication time stretches to hours. We solve this with automated type generation, ISR revalidation, and optimized Rich Text rendering. Our engineers hold Contentful certifications and have 10+ projects behind them — we guarantee results. Contact us for a demo of the ready solution.
Recently, a client with an e-commerce store on Next.js experienced slowdowns due to missing ISR and weak typings. After implementing our integration, page load times dropped 3x, and publication errors vanished.
Why Typing Content Types Saves Days of Development?
Manually writing TypeScript interfaces for Contentful models is a common source of bugs and desynchronization. We use cf-content-types-generator, which automatically produces strictly typed interfaces based on Content Types. This cuts development time by 40% and eliminates field access errors. When the content model changes in the admin, just rerun the generator and types update automatically. This prevents desynchronization and lets developers see errors immediately in the IDE.
npx cf-content-types-generator \ --spaceId $CONTENTFUL_SPACE_ID \ --token $CONTENTFUL_MANAGEMENT_TOKEN \ --out src/types/contentful.ts \ --v10 Result — typed fields, including links to other entries and dates:
export interface TypeBlogPostFields { title: EntryFieldTypes.Symbol; slug: EntryFieldTypes.Symbol; body: EntryFieldTypes.RichText; heroImage: EntryFieldTypes.AssetLink; author: EntryFieldTypes.EntryLink<TypeAuthorSkeleton>; publishedAt: EntryFieldTypes.Date; tags: EntryFieldTypes.Array<EntryFieldTypes.Symbol>; } How to Set Up ISR with Webhooks Without Full Rebuild?
ISR (Incremental Static Regeneration) updates pages on demand. Step by step:
- Set
revalidatein Next.js (e.g., 3600 seconds). - Create an API route for the webhook that calls
revalidatePath. - In Contentful, configure a webhook on the entry publish event.
Client and route code:
// lib/contentful.ts import { createClient } from 'contentful'; const client = createClient({ space: process.env.CONTENTFUL_SPACE_ID!, accessToken: process.env.CONTENTFUL_DELIVERY_TOKEN!, }); export async function getBlogPosts() { const entries = await client.getEntries<TypeBlogPostSkeleton>({ content_type: 'blogPost', order: ['-fields.publishedAt'], include: 2, }); return entries.items; } export const revalidate = 3600; export async function generateStaticParams() { const posts = await getBlogPosts(); return posts.map((post) => ({ slug: post.fields.slug })); } export default async function BlogPostPage({ params }) { const post = await getPostBySlug(params.slug); return <BlogPost post={post} />; } // app/api/revalidate/route.ts import { revalidatePath, revalidateTag } from 'next/cache'; export async function POST(request: Request) { const secret = request.headers.get('x-contentful-webhook-secret'); if (secret !== process.env.CONTENTFUL_WEBHOOK_SECRET) { return Response.json({ error: 'Unauthorized' }, { status: 401 }); } const body = await request.json(); const slug = body.fields?.slug?.['en-US']; if (slug) { revalidatePath(`/blog/${slug}`); revalidateTag('blog-posts'); } return Response.json({ revalidated: true }); } This approach ensures users see the latest content without a full site rebuild. Publication time drops from hours to seconds. Learn more about ISR in the Next.js docs.
How to Render Rich Text with Custom Nodes?
The Rich Text field contains an AST. For rendering we use @contentful/rich-text-react-renderer with custom nodes. This allows embedding images, code, and links.
import { documentToReactComponents, Options } from '@contentful/rich-text-react-renderer'; import { BLOCKS, INLINES, MARKS } from '@contentful/rich-text-types'; const renderOptions: Options = { renderNode: { [BLOCKS.EMBEDDED_ASSET]: (node) => { const asset = node.data.target; return ( <Image src={`https:${asset.fields.file.url}`} width={asset.fields.file.details.image.width} height={asset.fields.file.details.image.height} alt={asset.fields.description || asset.fields.title} className="rounded-lg my-6" /> ); }, [BLOCKS.EMBEDDED_ENTRY]: (node) => { const entry = node.data.target; if (entry.sys.contentType.sys.id === 'codeBlock') { return <CodeBlock code={entry.fields.code} lang={entry.fields.language} />; } return null; }, [INLINES.HYPERLINK]: (node, children) => ( <a href={node.data.uri} target="_blank" rel="noopener noreferrer">{children}</a> ), }, renderMark: { [MARKS.CODE]: (text) => <code className="bg-muted px-1 rounded">{text}</code>, }, }; This allows editors to embed images, code blocks, and other inline objects without developer involvement.
How Gatsby Simplifies Contentful Integration?
Installing gatsby-source-contentful gives ready-made nodes in GraphQL. Setup takes 15 minutes — just provide Space ID and token. Then query content via standard GraphQL. Compared to Strapi, Contentful is 2x faster for volumes over 10k entries (benchmark data). For large projects with hundreds of entries, we recommend using pagination and caching at the BFF layer.
What’s Included in the Work
- Contentful client setup and typing of all Content Types.
- List and detail pages for each content type.
- Rich Text rendering with support for embedded links and images.
- ISR + on-demand revalidation via webhooks.
- Preview mode (Draft Mode) for draft previews.
- Image optimization via Contentful Images API.
- Documentation and team training.
Each step is documented so your team can maintain the integration independently. After completion, we provide a detailed guide on adding new content types.
Typical Integration Timeline
| Task | Time |
|---|---|
| Basic client setup + typing | 0.5 day |
| List and pages for one Content Type | 1 day |
| Rich Text renderer with custom nodes | 0.5–1 day |
| ISR + Webhook revalidation | 0.5 day |
| Preview Mode | 0.5 day |
| Full integration (5–10 Content Types) | 3–5 days |
Note: Timelines may vary depending on content model complexity and required functionality.
Common Pitfalls and How to Avoid Them
| Mistake | Solution |
|---|---|
| Missing typings | Use cf-content-types-generator |
| Slow loading | Enable ISR and optimize queries |
| Rich Text without custom nodes | Configure renderOptions |
| No preview | Enable draft mode with a separate token |
| Incorrect CORS settings for preview | In Contentful admin, specify your app domain |
We guarantee post-launch support: update types, fix bugs, tune caching. Contact us to discuss your project — get a consultation and budget estimate within 2 days. Order your Contentful integration today.







