Integrating Contentful CMS with Next.js Portfolio

Make your content dynamic without touching code again!
Want to update your portfolio without opening VS Code every time? That’s where Contentful CMS + Next.js becomes a powerful combo. In this post, I’ll show you how to connect your Contentful dashboard to your Next.js portfolio, step-by-step.
🧠What’s the idea here?
Instead of hardcoding all your portfolio data (like projects, blogs, testimonials) into.tsx
files, you can store and manage it in Contentful, a headless CMS. Then your Next.js site will fetch and display it automatically using Contentful’s APIs.
This setup means:
- âś… No redeployment needed for every content change
- âś… Non-techies can update content too
- âś… Fast and flexible front-end with server-rendered content
đź”§ Tech stack used
- Next.js (latest version, with App Router)
- Contentful (Free tier works great)
- TypeScript (Optional but recommended)
- Incremental Static Regeneration (ISR) for best performance
🪜 Step-by-Step Guide
1. 🏗️ Create a Contentful account
- Go to https://contentful.com
- Sign up → Create a new Space (name it like “My Portfolio”)
- Under that space, create Content Models for what you want to display (e.g., Projects, Blogs, Testimonials)
Example Model: “Project”
title
(Text)slug
(Text, unique identifier)description
(Long text or Rich Text)image
(Media → Image)link
(URL)
💡 You can later add more fields, like “technologies, experience, or about us.
2. đź§Ş Add some test content
- Go to “Content” → Add a few projects manually.
- Make sure to Publish them, or they won’t be fetched by your app.
3. 🔑 Get your Contentful API credentials
- Go to:
- Settings → API Keys → Create new API key
- Note down:
- Space ID
- Content Delivery API - Access Token
4. 🤖 Setup your Next.js project
If you haven’t already:
npx create-next-app@latest my-portfolio cd my-portfolio
Install Contentful SDK:
npm install contentful
Create a
.env.local
file in the root and add:
CONTENTFUL_SPACE_ID=your_space_id_here CONTENTFUL_ACCESS_TOKEN=your_access_token_here
5. 📦 Create a Contentful client
Insidelib/contentful.ts
:
import { createClient } from 'contentful'; export const contentfulClient = createClient({ space: process.env.CONTENTFUL_SPACE_ID!, accessToken: process.env.CONTENTFUL_ACCESS_TOKEN!, });
6. 📥 Fetch data from Contentful
Create a function like this inlib/projects.ts
:
import { contentfulClient } from './contentful'; export async function getProjects() { const response = await contentfulClient.getEntries({ content_type: 'project' }); return response.items.map((item: any) => ({ title: item.fields.title, slug: item.fields.slug, description: item.fields.description, image: item.fields.image?.fields.file.url, link: item.fields.link, })); }
Replace 'project'
with your actual content type ID (you’ll find this in Content Model → Settings → API Identifier).
7. đź’» Show it in your Next.js page
For example, inapp/projects/page.tsx
:
import { getProjects } from '@/lib/projects'; export default async function ProjectsPage() { const projects = await getProjects(); return ( <div className="p-6"> <h1 className="text-3xl font-bold mb-4">My Projects</h1> <ul className="grid grid-cols-1 md:grid-cols-2 gap-6"> {projects.map((proj) => ( <li key={proj.slug} className="border rounded-xl p-4 shadow-md"> <img src={proj.image} alt={proj.title} className="rounded-lg mb-2" /> <h2 className="text-xl font-semibold">{proj.title}</h2> <p className="text-gray-600">{proj.description}</p> <a href={proj.link} className="text-blue-500 mt-2 block" target="_blank">View Project</a> </li> ))} </ul> </div> ); }
8. ⚡ Use ISR for faster builds
You can usegenerateStaticParams
and revalidate
inside your Next.js App Router pages to cache and auto-update.
Inside
app/projects/page.tsx
:
export const revalidate = 60; // Revalidate every 60 seconds
9. đź§Ş Test it locally
Run your project:
npm run dev
Visit http://localhost:3000/projects – your dynamic Contentful data should now show up!
âś… Final Thoughts
Using Contentful with Next.js makes your portfolio super flexible and client-friendly. You just need to build the UI once, and from then on, you (or anyone else) can update the data from the CMS without touching the code.
📌 Bonus Tips
- You can connect multiple models like Blogs, Testimonials, Services, etc.
- Use Contentful’s Rich Text renderer if you want advanced formatting in content.
- Set up webhooks from Contentful to Vercel for instant redeploys.