Integrating MeshBase with Next.js
Build lightning-fast Next.js applications powered by MeshBase. Server Components, App Router, SSR, SSG—all the patterns you need.
Why MeshBase + Next.js?
⚡Server Components Ready
Fetch content server-side with Next.js 13+ App Router. Fast initial loads, SEO-friendly out of the box.
🎯ISR & SSG Support
Static generation with revalidation. Build fast sites that stay fresh with incremental updates.
🚀API Routes Compatible
Use MeshBase from Next.js API routes for server-side operations, webhooks, and custom logic.
🔄Flexible Data Fetching
Server Components, Client Components, getStaticProps, getServerSideProps—MeshBase works with all patterns.
What You'll Need
- ✓Next.js 13+ project (App Router or Pages Router)
- ✓A MeshBase account with content types defined
- ✓Your MeshBase API key (from Project Settings)
Quick Start: App Router (Next.js 13+)
Using the new App Router? Server Components make MeshBase integration dead simple.
1. Add your API key
Create .env.local:
MESHBASE_API_URL=https://api.meshbase.io/v1
MESHBASE_API_KEY=your-api-key-here2. Create a data fetcher
Create lib/meshbase.ts:
const API_URL = process.env.MESHBASE_API_URL;
const API_KEY = process.env.MESHBASE_API_KEY;
export async function fetchFromMeshBase(endpoint: string) {
const res = await fetch(`${API_URL}${endpoint}`, {
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
next: { revalidate: 60 } // ISR: revalidate every 60s
});
if (!res.ok) throw new Error('Failed to fetch from MeshBase');
return res.json();
}
// Typed helper for blog posts
export async function getBlogPosts() {
const { data } = await fetchFromMeshBase('/blog-posts');
return data;
}
export async function getBlogPost(id: string) {
const data = await fetchFromMeshBase(`/blog-posts/${id}`);
return data;
}3. Use in Server Components
Create app/blog/page.tsx:
import { getBlogPosts } from '@/lib/meshbase';
export default async function BlogPage() {
const posts = await getBlogPosts();
return (
<div>
<h1>Blog</h1>
<div className="grid gap-6">
{posts.map((post) => (
<article key={post.id}>
<h2>{post.title}</h2>
<p>{post.excerpt}</p>
<a href={`/blog/${post.id}`}>Read more</a>
</article>
))}
</div>
</div>
);
}That's It!
Your Next.js app now fetches content from MeshBase server-side. Fast initial loads, SEO-friendly, and automatically revalidated every 60 seconds.
Dynamic Routes
Build dynamic blog post pages with static generation.
Create app/blog/[id]/page.tsx:
import { getBlogPost, getBlogPosts } from '@/lib/meshbase';
// Generate static paths at build time
export async function generateStaticParams() {
const posts = await getBlogPosts();
return posts.map((post) => ({ id: post.id }));
}
export default async function BlogPostPage({
params
}: {
params: { id: string }
}) {
const post = await getBlogPost(params.id);
return (
<article>
<h1>{post.title}</h1>
{post.coverImage && (
<img src={post.coverImage} alt={post.title} />
)}
<div dangerouslySetInnerHTML={{ __html: post.content }} />
</article>
);
}Static Generation with ISR
This pattern generates static HTML at build time, then revalidates periodically. You get static site performance with dynamic content updates!
Pages Router (Next.js 12 and earlier)
Using the Pages Router? Here's the equivalent pattern.
Static Generation with getStaticProps
// pages/blog/index.tsx
import { getBlogPosts } from '@/lib/meshbase';
export async function getStaticProps() {
const posts = await getBlogPosts();
return {
props: { posts },
revalidate: 60 // ISR: revalidate every 60s
};
}
export default function BlogPage({ posts }) {
return (
<div>
<h1>Blog</h1>
{posts.map((post) => (
<article key={post.id}>
<h2>{post.title}</h2>
<p>{post.excerpt}</p>
</article>
))}
</div>
);
}Server-Side Rendering with getServerSideProps
// For real-time data (no caching)
export async function getServerSideProps() {
const posts = await getBlogPosts();
return {
props: { posts }
};
}Client-Side Data Fetching
Need to fetch data client-side? Use SWR or React Query.
Using SWR (Recommended)
Install: npm install swr
'use client';
import useSWR from 'swr';
const fetcher = (url: string) =>
fetch(url, {
headers: {
'Authorization': `Bearer ${process.env.NEXT_PUBLIC_MESHBASE_KEY}`
}
}).then(r => r.json());
export function BlogList() {
const { data, error, isLoading } = useSWR(
'https://api.meshbase.io/v1/blog-posts',
fetcher
);
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Failed to load</div>;
return (
<div>
{data.data.map((post) => (
<article key={post.id}>
<h2>{post.title}</h2>
</article>
))}
</div>
);
}Client vs Server API Keys
Use NEXT_PUBLIC_MESHBASE_KEY for client-side fetching. This should be your public read-only key, not your admin key!
Advanced Patterns
On-Demand Revalidation
Revalidate content when it changes in MeshBase using webhooks:
// app/api/revalidate/route.ts
import { revalidatePath } from 'next/cache';
import { NextRequest } from 'next/server';
export async function POST(request: NextRequest) {
const secret = request.nextUrl.searchParams.get('secret');
// Verify webhook secret
if (secret !== process.env.REVALIDATE_SECRET) {
return Response.json({ error: 'Invalid token' }, { status: 401 });
}
const body = await request.json();
// Revalidate the blog list
revalidatePath('/blog');
// Revalidate specific post
if (body.id) {
revalidatePath(`/blog/${body.id}`);
}
return Response.json({ revalidated: true });
}Parallel Data Fetching
// Fetch multiple collections in parallel
export default async function HomePage() {
const [posts, products] = await Promise.all([
getBlogPosts(),
getProducts()
]);
return (
<div>
<BlogSection posts={posts} />
<ProductSection products={products} />
</div>
);
}Next Steps
- →Handle images and media
Upload and serve media files
- →Explore the full API
Filtering, sorting, pagination, and more
- →Plain React integration
Using React without Next.js