A modern, production-ready starter for building content-managed websites with Agility CMS and Next.js 15.
New to Agility CMS? Sign up for a FREE account
- App Router - Modern Next.js routing with Server Components
- TypeScript - Full type safety throughout the project
- Tailwind CSS 4 - Utility-first styling with dark mode support
- Static Site Generation (SSG) - Pre-rendered pages with Incremental Static Regeneration (ISR)
- Server Components - React Server Components for optimal performance
- Dynamic Page Routing - Automatic page generation from Agility CMS sitemap
- Component Module System - CMS components mapped to React components
- Content Fetching - Server-side data fetching with caching strategies
- Preview Mode - Real-time content preview for editors
- On-Demand Revalidation - Webhook-triggered cache invalidation
- Multi-Locale Ready - Framework supports multiple languages
- Component-Level Data Fetching - Fetch data where you need it
- Cache Tag Strategy - Granular cache control with automatic invalidation
- Dark Mode - Built-in dark mode toggle with persistence
- Responsive Design - Mobile-first responsive layout
- Image Optimization - Next.js Image component integration
- TypeScript Interfaces - Strongly typed CMS content models
- Quick Start
- Project Structure
- Architecture
- Content Models
- Components
- Data Fetching
- Caching Strategy
- Preview Mode
- Deployment
- Advanced Guides
- Node.js 18.x or higher
- npm or yarn package manager
- An Agility CMS instance (sign up for free)
-
Clone the repository
git clone https://github.com/agility/agilitycms-nextjs-starter.git cd agilitycms-nextjs-starter -
Install dependencies
npm install # or yarn install -
Configure environment variables
cp .env.local.example .env.local
-
Get your API keys from Agility CMS
- Log into Agility CMS
- Navigate to Settings > API Keys
- Copy your:
- GUID (Instance ID)
- Live API Key (for production)
- Preview API Key (for development/preview)
- Security Key (for webhooks)
-
Update
.env.localwith your credentials:AGILITY_GUID=your-guid-here AGILITY_API_FETCH_KEY=your-live-api-key AGILITY_API_PREVIEW_KEY=your-preview-api-key AGILITY_SECURITY_KEY=your-security-key AGILITY_LOCALES=en-us AGILITY_SITEMAP=website AGILITY_FETCH_CACHE_DURATION=120 AGILITY_PATH_REVALIDATE_DURATION=10
-
Run the development server
npm run dev # or yarn dev -
Open your browser to http://localhost:3000
npm run build
npm run startagilitycms-nextjs-starter/
βββ app/ # Next.js App Router
β βββ layout.tsx # Root layout with header/footer
β βββ page.tsx # Home page (delegates to [...slug])
β βββ [...slug]/ # Dynamic catch-all route
β β βββ page.tsx # Main page component with SSG
β β βββ error.tsx # Error boundary
β β βββ not-found.tsx # 404 page
β βββ api/ # API routes
β βββ preview/ # Preview mode endpoints
β βββ preview/exit/ # Exit preview mode
β βββ revalidate/ # Webhook for cache invalidation
β βββ dynamic-redirect/ # ContentID-based redirects
βββ components/ # React components
β βββ agility-components/ # CMS component modules
β β βββ FeaturedPost.tsx # Featured post display
β β βββ PostDetails.tsx # Dynamic post detail view
β β βββ PostsListing/ # Infinite scroll post list
β β βββ TextBlockWithImage.tsx # Flexible layout component
β β βββ RichTextArea.tsx # HTML content display
β β βββ Heading.tsx # Typography component
β β βββ index.ts # Component registry
β βββ agility-pages/ # Page templates
β β βββ MainTemplate.tsx # Main page template
β β βββ index.ts # Template registry
β βββ common/ # Shared components
β βββ SiteHeader.tsx # Responsive header with dark mode
β βββ SiteFooter.tsx # Footer with social links
β βββ PreviewBar.tsx # Preview/Live mode toggle
β βββ InlineError.tsx # Error display
βββ lib/ # Utilities and helpers
β βββ cms/ # CMS data fetching
β β βββ getAgilityContext.ts # Mode detection (preview/live)
β β βββ getAgilitySDK.ts # SDK initialization
β β βββ getAgilityPage.ts # Fetch pages with layout
β β βββ getContentItem.ts # Fetch single content item
β β βββ getContentList.ts # Fetch content lists
β β βββ getSitemapFlat.ts # Flat sitemap retrieval
β β βββ getSitemapNested.ts # Nested sitemap retrieval
β βββ cms-content/ # Domain-specific queries
β β βββ getPostListing.ts # Blog posts with URLs
β β βββ getHeaderContent.ts # Header navigation data
β β βββ getPageMetaData.ts # Page SEO metadata
β β βββ resolveAgilityMetaData.ts # Advanced metadata
β βββ types/ # TypeScript interfaces
β βββ (IPost, IAuthor, ICategory, etc.)
βββ styles/
β βββ globals.css # Tailwind imports & global styles
βββ middleware.ts # Next.js middleware for routing
βββ .env.local.example # Environment template
βββ tailwind.config.js # Tailwind configuration
βββ next.config.js # Next.js configuration
βββ tsconfig.json # TypeScript configuration
This starter uses Next.js App Router with a catch-all dynamic route [...slug] that maps to Agility CMS pages.
How it works:
- Agility CMS sitemap defines your site structure
generateStaticParams()pre-renders all pages at build time- Each page fetches its layout template and content zones from Agility
- Components are dynamically loaded based on CMS configuration
See ARCHITECTURE.md for detailed explanation.
CMS components (modules) are mapped to React components via a registry pattern:
// components/agility-components/index.ts
const allModules = [
{name: "TextBlockWithImage", module: TextBlockWithImage},
{name: "Heading", module: Heading},
{name: "FeaturedPost", module: FeaturedPost},
{name: "PostsListing", module: PostsListing},
{name: "PostDetails", module: PostDetails},
{name: "RichTextArea", module: RichTextArea},
]When Agility CMS returns a page with a "TextBlockWithImage" module, the system automatically renders the corresponding React component.
This starter uses React Server Components for optimal performance:
- Server Components - Default for all components, fetch data server-side
- Client Components - Used only when necessary (interactive features, hooks)
- Component-level fetching - Each component fetches its own data
- Parallel data fetching - Multiple components fetch concurrently
Example:
// Server Component (default)
export default async function PostDetails({module, page}) {
const post = await getContentItem({contentID: page.contentID})
return <article>...</article>
}The Agility CMS instance includes the following content models:
- Post - Blog posts with category, tags, author, image, and rich content
- Author - Author profiles with name, title, and headshot
- Category - Post categories with images and descriptions
- Tag - Post tags for classification
- Header - Site header with navigation and logo
- Footer - Site footer with links and social media
- Global Settings - Site-wide configuration
- Testimonial Item - Customer testimonials
- FAQ Item - Frequently asked questions
- Pricing Tier - Pricing plans and features
- Carousel Slide - Carousel content items
- Audience - Custom demographic targeting
- Region - Geographic personalization
- Customer Profile - User profiles for personalization
See CONTENT-MODELS.md for complete schema documentation.
- MainTemplate - Standard page layout with content zones
- PostsListing - Paginated blog post list with infinite scroll
- PostDetails - Individual post view with author, category, and rich content
- FeaturedPost - Highlighted post display
- TextBlockWithImage - Flexible text + image layout (left/right)
- RichTextArea - Rich HTML content with Tailwind prose styling
- Heading - Page headings with various styles
- SiteHeader - Responsive navigation with dark mode toggle
- SiteFooter - Footer with social links and copyright
- PreviewBar - Preview mode indicator (development only)
See COMPONENTS.md for complete component API documentation.
Located in lib/cms/, these utilities handle all Agility CMS interactions:
Determines the current mode (preview vs. production):
const context = await getAgilityContext()
// Returns: { isPreview: boolean, locale: string, sitemap: string }Fetches a single content item with cache tags:
const post = await getContentItem({
contentID: 123,
languageCode: "en-us",
})Fetches content lists with pagination and filtering:
const posts = await getContentList({
referenceName: "posts",
languageCode: "en-us",
take: 10,
skip: 0,
sort: "fields.date",
direction: "desc",
})Fetches a complete page with layout and content zones:
const page = await getAgilityPage({
slug: "/blog",
locale: "en-us",
sitemap: "website",
})Located in lib/cms-content/, these build on the CMS utilities for specific use cases:
getPostListing()- Blog posts with category filtering and URLsgetHeaderContent()- Navigation structure and brandinggetPageMetaData()- SEO metadata for pages
See AGILITY-CMS-GUIDE.md for complete data fetching patterns.
This starter implements a sophisticated caching strategy for optimal performance:
-
SDK Object Cache - Agility Fetch SDK caches content items
- Controlled by
AGILITY_FETCH_CACHE_DURATION(default: 120 seconds) - Works best with on-demand revalidation
- Controlled by
-
Next.js Route Cache - Next.js caches rendered pages
- Controlled by
AGILITY_PATH_REVALIDATE_DURATION(default: 10 seconds) - ISR (Incremental Static Regeneration) automatically updates stale pages
- Controlled by
Content fetches use cache tags for granular invalidation:
// Automatically tagged as: agility-content-{contentID}-{locale}
const post = await getContentItem({contentID: 123})When content is published in Agility CMS, a webhook triggers revalidation:
- Tags associated with changed content are invalidated
- Next.js regenerates affected pages on the next request
The /api/revalidate endpoint handles webhook callbacks from Agility CMS:
// Revalidates specific content items and their dependent pages
POST /api/revalidate
{
"contentID": 123,
"languageCode": "en-us"
}# Cache content objects for 120 seconds
AGILITY_FETCH_CACHE_DURATION=120
# Revalidate page paths every 10 seconds
AGILITY_PATH_REVALIDATE_DURATION=10Best Practices:
- Use higher values (120-600) with on-demand revalidation for production
- Use lower values (10-30) or
0without webhooks for faster content updates - Preview mode always bypasses cache for real-time editing
Preview mode allows content editors to see draft content before publishing.
- Activate Preview - Click "Preview" in Agility CMS
- Validation - System validates preview key and ContentID
- Draft Mode - Next.js draft mode is enabled
- Live Preview - Page displays with unpublished content
- Exit - Click "Exit Preview" in the preview bar
Preview Endpoint (app/api/preview/route.ts):
// Validates request and enables draft mode
export async function GET(request: Request) {
const {agilitypreviewkey, ContentID, slug} = searchParams
// Validate preview key
if (agilitypreviewkey !== process.env.AGILITY_SECURITY_KEY) {
return new Response("Invalid token", {status: 401})
}
// Enable draft mode
draftMode().enable()
// Redirect to preview page
redirect(slug)
}Middleware (middleware.ts):
// Intercepts preview requests before they reach pages
export function middleware(request: NextRequest) {
const {pathname, searchParams} = request.nextUrl
if (searchParams.has("agilitypreviewkey")) {
// Rewrite to preview API for validation
return NextResponse.rewrite(new URL("/api/preview", request.url))
}
}Preview Bar (components/common/PreviewBar.tsx):
- Shows when in preview/development mode
- Displays current mode (Preview/Live)
- Provides exit button to leave preview mode
Set your security key in .env.local:
AGILITY_SECURITY_KEY=your-security-key-from-agilityThis key must match the one configured in Agility CMS webhook settings.
Vercel provides the best Next.js experience with zero configuration:
- Push to GitHub - Commit your code to a GitHub repository
- Import to Vercel - Connect your repo at vercel.com
- Configure Environment Variables - Add your
.env.localvalues - Deploy - Vercel automatically builds and deploys
Environment Variables to Set:
AGILITY_GUID
AGILITY_API_FETCH_KEY
AGILITY_API_PREVIEW_KEY
AGILITY_SECURITY_KEY
AGILITY_LOCALES
AGILITY_SITEMAP
AGILITY_FETCH_CACHE_DURATION
AGILITY_PATH_REVALIDATE_DURATION
Configure Webhooks in Agility CMS:
- Navigate to Settings > Webhooks
- Add webhook URL:
https://your-site.vercel.app/api/revalidate - Set trigger: "Content Published"
- Push to GitHub
- Import to Netlify - Connect your repo at netlify.com
- Build Settings:
- Build command:
npm run build - Publish directory:
.next
- Build command:
- Environment Variables - Add your
.env.localvalues - Deploy
This starter can deploy to any platform supporting Next.js:
- AWS Amplify
- Digital Ocean App Platform
- Railway
- Render
Ensure your platform supports:
- Node.js 18+
- Next.js 15
- On-demand revalidation (optional but recommended)
This starter is designed to work seamlessly with AI coding assistants like Claude Code, GitHub Copilot, Cursor, and ChatGPT for rapid development.
"Vibe coding" is the practice of using AI assistants to help you build features by describing what you want in natural language, rather than writing every line of code manually. This starter's comprehensive documentation makes it perfect for AI-assisted development.
- Complete Documentation - All patterns and schemas are documented, giving AI context
- Type Safety - TypeScript interfaces help AI understand data structures
- Consistent Patterns - Clear architectural patterns AI can follow
- Example Code - Real implementations AI can reference
- Open this README in your editor - AI assistants have full context
- Ask natural language questions:
- "Add a new component that displays team members in a grid"
- "Create a contact form component with validation"
- "Add a hero section with background image support"
- "Implement multi-locale routing"
- AI will:
- Reference the documentation
- Follow existing patterns
- Create properly typed code
- Register components correctly
Create a new component:
Create a "TeamGrid" component that:
- Fetches team members from a "teammembers" container
- Displays them in a responsive 3-column grid
- Shows name, title, photo, and bio
- Supports dark mode
- Follows the same patterns as PostsListing
Add a feature:
Add search functionality to the PostsListing component:
- Add a search input at the top
- Filter posts by title/content as user types
- Maintain infinite scroll behavior
- Use client component for interactivity
Extend existing code:
Looking at TextBlockWithImage component, create a similar
"ImageGallery" component that shows multiple images in a grid
with lightbox functionality.
This project includes the Agility CMS MCP Server configuration in .vscode/mcp.json, which gives AI coding assistants (like Claude Code) direct access to your CMS instance through the Model Context Protocol.
What is MCP?
MCP (Model Context Protocol) is a standard that allows AI assistants to connect to external services. The Agility MCP Server acts as a bridge between your AI assistant and your Agility CMS instance, providing real-time access to your content structure and data.
What AI can do with MCP:
- β Query content models - See the exact schema of your Posts, Products, etc.
- β List content items - Browse actual content from your CMS
- β Inspect field types - Know if a field is text, image, linked content, etc.
- β Generate accurate interfaces - Create TypeScript types that match your CMS exactly
- β Validate component code - Ensure components use correct field names
- β Build smart queries - Create filters based on actual available fields
Example Workflows with MCP:
Creating a new component:
Use the Agility MCP server to get the "Products" content model,
then create:
1. A TypeScript interface (IProduct) with all fields
2. A ProductGrid component with category filtering
3. A domain helper (getProductListing) for data fetching
4. Register the component in the index
Validating existing code:
Query the Agility MCP server for the "TeamMembers" model and
verify that the ITeamMember interface in lib/types/ has all
the correct fields with proper types.
Discovering opportunities:
Use MCP to list all content models in my instance, then
suggest 5 new components I could build based on unused models.
Why MCP Makes AI Development Better:
| Without MCP | With MCP |
|---|---|
| AI guesses field names | AI sees exact field names |
| AI assumes field types | AI knows actual field types |
| Trial and error fixing typos | Works first time |
| Generic component templates | CMS-specific, accurate code |
| Manual schema documentation | Direct CMS inspection |
Getting Started with MCP:
- Ensure
.vscode/mcp.jsonexists - Already configured in this project - Use Claude Code or compatible AI - MCP is supported by Claude and others
- Reference MCP in prompts - Say "Use the Agility MCP server to..."
- Let AI query your CMS - AI will fetch schemas and data automatically
MCP Server Configuration:
The project includes a pre-configured MCP connection:
// .vscode/mcp.json
{
"servers": {
"Agility CMS": {
"url": "https://mcp.agilitycms.com/api/mcp",
"type": "http"
}
}
}This connects to the public Agility MCP server, which requires your API keys (from .env.local) to access your specific instance.
Learn More:
- Model Context Protocol
- Agility MCP Server Documentation (coming soon)
For more advanced examples including AI integration, personalization, and complex patterns, see:
This repository includes:
- AI-powered search with streaming responses
- Multi-locale implementation (3+ languages)
- Personalization system (audience/region targeting)
- A/B testing components
- Advanced caching strategies
- 27+ production-ready components
- Complete documentation for AI assistants
Use it as a reference when asking AI to build advanced features:
Looking at the nextjs-demo-site-2025 repo, implement a similar
AI search modal for this project.
-
Reference Documentation - Point AI to specific docs:
- "Following docs/ARCHITECTURE.md, add..."
- "Using patterns from docs/AGILITY-CMS-GUIDE.md, create..."
- "Based on docs/COMPONENTS.md examples, build..."
-
Provide Context - Share your CMS structure:
- "My 'Products' model has these fields: ..."
- "I have a container called 'testimonials' with..."
-
Request Tests - Ask AI to validate:
- "Create this component and test it renders correctly"
- "Add error handling for missing data"
-
Iterate - Refine in steps:
- Start with basic version
- Add features incrementally
- Request optimizations
-
Use Type Safety - Let AI leverage TypeScript:
- "Generate the TypeScript interface first"
- "Ensure all props are properly typed"
1. Describe Feature β AI generates component
β
2. Review Code β AI refines based on feedback
β
3. Create CMS Model β AI generates TypeScript interface
β
4. Register Component β AI updates index file
β
5. Test & Iterate β AI fixes issues
This documentation-first approach makes AI assistants highly effective at extending this starter with new features, components, and integrations.
Detailed documentation for specific topics:
- QUICK-START-AI.md - Quick reference for AI assistants (start here for vibe coding!)
- ARCHITECTURE.md - Deep dive into code structure and patterns
- AGILITY-CMS-GUIDE.md - CMS integration patterns and best practices
- COMPONENTS.md - Component API reference and usage
- CONTENT-MODELS.md - Complete CMS schema documentation
AI Assistant Configuration:
.cursorrules- Rules for Cursor, Claude Code, and other AI tools (auto-loaded)
Shows latest content in real-time (uses Preview API Key):
npm run devShows published content (uses Live API Key):
npm run build
npm run startThis project uses TypeScript with strict mode. Type definitions for CMS content are in lib/types/.
npm run lint- ESLint - Configured with
next/core-web-vitals - Prettier - (Optional) Add
.prettierrcfor consistent formatting
Contributions are welcome! Please feel free to submit a Pull Request.
If you have feedback or questions about this starter:
- GitHub Issues - Report bugs or request features
- Community Slack - Join our Slack community
- Support - Email support@agilitycms.com
This project is licensed under the MIT License.
Made with β€οΈ by Agility CMS