AI-powered blog generation and content delivery built exclusively for Next.js applications. Designed from the ground up to work seamlessly with Next.js App Router and Pages Router, providing optimized solutions for React Server Components, static site generation, and incremental static regeneration.
Before using this package: You need to sign up and set up your blog content service at next-blog-ai.com.
This package is the client library that connects to the Next-Blog-AI service where you'll:
- Manage your account and subscription
- Configure content generation settings
- Monitor analytics and performance
- Get your API key for connecting via this package
Sign up at next-blog-ai.com to get started.
- Optimized for Next.js App Router architecture
- Blog post listing and detail views
- Supports both HTML and JSON response formats
- Built-in caching mechanism with Next.js-specific optimizations and configurable TTL
- Response normalization (snake_case to camelCase)
- Automatic retries with exponential backoff
- Concurrent request deduplication
- HTML content styling with customizable CSS
- TypeScript support with comprehensive type definitions
- App Router Optimization: Built specifically for Next.js 13+ App Router architecture
- Server Components: First-class support for React Server Components
- ISR Support: Deep integration with Incremental Static Regeneration
- Metadata API: Optimized for Next.js Metadata API
- Edge Runtime: Compatible with Next.js Edge Runtime
-
Static Exports: Support for
generateStaticParams
and static generation
You have two options to install Next-Blog-AI in your Next.js project:
Use our automated setup tool which handles everything for you:
npx create-next-blog-ai@latest
This command will:
- Install the Next-Blog-AI package automatically
- Set up the client in your project
- Configure the necessary files for blog functionality
If you prefer a manual approach, first install the package:
npm install next-blog-ai
# or
yarn add next-blog-ai
# or
pnpm add next-blog-ai
Then you'll need to configure the client yourself (see the Advanced Manual Setup section below).
If you prefer to set up the client manually or need more customization, follow the steps below:
For the best experience in Next.js projects, we provide a specialized Next.js client creator that simplifies integration:
// lib/next-blog-ai.ts
import { createNextBlogAIForNextJs } from 'next-blog-ai';
// Create a Next.js-optimized client with all methods ready to use with Next.js caching
export const {
client, // The base client instance
getBlogPosts, // List posts
getBlogPost, // Get single post
getBlogPostSEO, // Get post SEO
getBlogListSEO, // Get list SEO
getAllBlogSlugs, // Get all slugs
} = createNextBlogAIForNextJs(process.env.NEXT_BLOG_AI_API_KEY!);
Then import and use these functions throughout your Next.js application:
// app/blog/page.tsx
import { getBlogPosts } from '@/lib/next-blog-ai';
export default async function BlogPage() {
// Using the Next.js-optimized function with default caching
const { data, error } = await getBlogPosts();
// Or override the default cache settings
const { data: freshData } = await getBlogPosts({
next: {
revalidate: 0, // Dynamic rendering for this request only
},
});
// Rest of your component...
}
This approach gives you:
- Proper typing for all Next.js-specific options
- Simplified imports across your Next.js application
- Consistent caching defaults that can be overridden when needed
- Full compatibility with both App Router and Pages Router
For comprehensive documentation, guides, and examples, please visit our official documentation site:
Our documentation includes detailed information about installation, API reference, advanced usage examples, and best practices for Next.js integration.
// Get a list of blog posts in a Next.js Server Component
const { data, error } = await nextBlogAI.getBlogPosts({
page: 1,
perPage: 10,
format: 'json', // 'html' or 'json'
display: 'list', // 'grid' or 'list' (only applies to HTML format)
// Next.js-specific caching options
next: {
revalidate: 3600, // ISR with 1-hour revalidation
},
});
if (error) {
console.error('Error fetching blog posts:', error);
} else {
console.log('Blog posts:', data);
}
// Get a single blog post by slug in a Next.js Server Component
const { data, error } = await nextBlogAI.getBlogPost('hello-world', {
format: 'html',
// Next.js-specific caching options
next: {
revalidate: 3600, // ISR with 1-hour revalidation
},
});
if (error) {
console.error('Error fetching blog post:', error);
} else {
console.log('Blog post:', data);
}
// Submit a comment on a blog post (works great with Next.js Server Actions)
const { data, error } = await nextBlogAI.submitComment({
postId: '123',
authorName: 'John Doe',
authorEmail: 'john@example.com', // Optional
content: 'Great article! Thanks for sharing.',
});
if (error) {
console.error('Error submitting comment:', error);
} else {
console.log('Comment submitted:', data);
}
// In a Next.js Server Component (app/blog/page.tsx)
import { nextBlogAI } from '@/lib/next-blog-ai';
export default async function BlogPage() {
const { data, error } = await nextBlogAI.getBlogPosts({
next: {
revalidate: 3600, // Enable ISR and revalidate every hour
},
});
if (error) {
return <div>Error loading blog posts: {error.message}</div>;
}
if (data.format === 'html') {
return <div dangerouslySetInnerHTML={{ __html: data.content }} />;
} else {
return (
<div>
{data.posts.map((post) => (
<article key={post.id}>
<h2>{post.title}</h2>
<p>{post.excerpt}</p>
</article>
))}
</div>
);
}
}
// In app/blog/[slug]/page.tsx
import { nextBlogAI } from '@/lib/next-blog-ai';
export default async function BlogPostPage({
params,
}: {
params: Promise<{ slug: string }>;
}) {
// Important: await the params, following Next.js App Router patterns
const { slug } = await params;
const { data, error } = await nextBlogAI.getBlogPost(slug, {
next: {
revalidate: 3600, // Enable ISR and revalidate every hour
},
});
if (error) {
return <div>Error loading blog post: {error.message}</div>;
}
return (
<>
{data.format === 'html' ? (
<>
<div dangerouslySetInnerHTML={{ __html: data.content }} />
<div dangerouslySetInnerHTML={{ __html: data.comments }} />
<div dangerouslySetInnerHTML={{ __html: data.commentForm }} />
</>
) : (
<>
<h1>{data.post.title}</h1>
<div>{data.post.content}</div>
<h2>Comments</h2>
{data.comments.map((comment) => (
<div key={comment.id}>
<strong>{comment.authorName}</strong>
<p>{comment.content}</p>
</div>
))}
{/* Your custom comment form */}
</>
)}
</>
);
}
You can customize the styles for both blog content and blog listings:
import { createNextBlogAI, DEFAULT_BLOG_STYLES } from 'next-blog-ai';
// Create client with custom styles
const nextBlogAI = createNextBlogAI({
apiKey: 'your-api-key',
styles: {
blogContent: `
${DEFAULT_BLOG_STYLES}
/* Your custom overrides */
.next-blog-ai-content h1 {
color: #0070f3;
font-size: 2.5rem;
}
`,
blogList: '/* Your custom CSS for blog listings */',
},
});
// Or set styles later
nextBlogAI.setStyles({
blogContent: '/* Your custom CSS for blog posts */',
blogList: '/* Your custom CSS for blog listings */',
});
// Clear the entire cache
nextBlogAI.clearCache();
// Clear a specific item from the cache
nextBlogAI.clearCacheItem('list', { page: 1, per_page: 10 });
const { data, error } = await nextBlogAI.getBlogPosts();
if (error) {
if (error.status === 401) {
console.error('Authentication error. Check your API key.');
} else if (error.status === 429) {
console.error('Rate limit exceeded. Please try again later.');
} else if (error.status >= 500) {
console.error('Server error. Please try again later.');
} else {
console.error(`Error: ${error.message}`);
}
}
-
createNextBlogAIForNextJs(apiKey, defaultCacheOptions)
- Create a Next.js-optimized client -
getBlogPosts(options)
- Get a list of blog posts with Next.js caching -
getBlogPost(slug, options)
- Get a single blog post with Next.js caching -
getBlogPostSEO(slug, options)
- Fetch only SEO metadata for a post with Next.js caching -
getBlogListSEO(options)
- Fetch only SEO metadata for blog list with Next.js caching -
getAllBlogSlugs(options)
- Get all blog post slugs with Next.js caching (for static site generation) -
submitComment(data)
- Submit a comment on a blog post
Option | Type | Description |
---|---|---|
revalidate |
number |
Next.js revalidation time in seconds (ISR) |
dynamic |
boolean |
Force dynamic rendering without caching |
Option | Type | Default | Description |
---|---|---|---|
apiKey |
string |
Required | API key for authentication |
defaultFormat |
'html' | 'json' |
'html' |
Default format for content responses |
defaultBlogListDisplay |
'grid' | 'list' |
'grid' |
Default display format for blog lists |
defaultCacheTTL |
number |
0 |
Default cache TTL in seconds (0 = no caching) |
retry |
RetryOptions |
See below | Configuration for request retries |
styles |
{ blogContent?: string, blogList?: string } |
Default styles | Custom CSS styles for HTML content |
Option | Type | Default | Description |
---|---|---|---|
maxRetries |
number |
3 |
Maximum number of retry attempts |
initialDelay |
number |
300 |
Initial delay before first retry (ms) |
backoffFactor |
number |
2 |
Factor by which to increase delay after each retry |
maxDelay |
number |
10000 |
Maximum delay between retries (ms) |
jitter |
boolean |
true |
Whether to add jitter to retry delays |
MIT
Next-Blog-AI automatically generates SEO metadata for all blog posts at the time they are created. This metadata includes:
- SEO Title: An optimized title for search engines
- Meta Description: A compelling description that includes relevant keywords
- Keywords: Primary and related keywords relevant to the content
- Featured Image: Image data for social media sharing (Open Graph, Twitter cards)
- Structured Data: JSON-LD markup for Schema.org that helps search engines understand the content
This SEO metadata is stored in the database and returned with each blog post request, so there's no delay in generating it on-demand. The API returns this SEO metadata in both formats (HTML and JSON) as part of the response.
// When using the HTML format
const { data } = await getBlogPost('my-post-slug', { format: 'html' });
// Set document metadata (example with Next.js)
export const metadata: Metadata = {
title: data.seo.title,
description: data.seo.description,
keywords: data.seo.keywords.join(', '),
// Add Open Graph and Twitter metadata if a featured image is available
...(data.seo.featuredImage
? {
openGraph: {
images: [
{
url: data.seo.featuredImage.url,
width: 1200,
height: 630,
alt: data.seo.featuredImage.alt,
},
],
},
twitter: {
card: 'summary_large_image',
images: [data.seo.featuredImage.url],
},
}
: {}),
};
// Add Schema.org structured data to your page
<script
type='application/ld+json'
dangerouslySetInnerHTML={{ __html: JSON.stringify(data.seo.structuredData) }}
/>;
For pages that only need SEO metadata (like in Next.js generateMetadata
functions), you can use our optimized SEO-only functions:
// For blog post detail pages
export async function generateMetadata({ params }): Promise<Metadata> {
const { slug } = await params;
const { data, error } = await nextBlogAI.getBlogPostSEO(slug, {
cache: { ttl: 3600 }, // Cache for 1 hour
});
if (error || !data) {
return { title: 'Blog Post', description: 'Default description' };
}
return {
title: data.seo.title,
description: data.seo.description,
keywords: data.seo.keywords.join(', '),
};
}
// For blog list pages
export async function generateMetadata(): Promise<Metadata> {
const { data, error } = await nextBlogAI.getBlogListSEO({
cache: { ttl: 3600 }, // Cache for 1 hour
});
if (error || !data) {
return { title: 'Blog', description: 'Default description' };
}
return {
title: data.seo.title,
description: data.seo.description,
keywords: data.seo.keywords.join(', '),
};
}
These optimized functions only fetch the SEO metadata without retrieving the full content, significantly improving performance and reducing bandwidth usage for metadata-only operations.
For static site generation in Next.js, you can use the getAllBlogSlugs
function to get a list of all blog post slugs:
// pages/blog/[slug].tsx (Next.js Pages Router)
import { createNextBlogAI } from 'next-blog-ai';
const nextBlogAI = createNextBlogAI({
apiKey: process.env.NEXT_BLOG_AI_API_KEY!,
});
// Get all available blog post slugs for static paths
export async function getStaticPaths() {
const { data, error } = await nextBlogAI.getAllBlogSlugs();
if (error || !data) {
// Handle error or provide fallback
return { paths: [], fallback: 'blocking' };
}
// Generate static paths from the slugs
return {
paths: data.slugs.map((slug) => ({ params: { slug } })),
fallback: 'blocking', // or false if you only want to pre-render known paths
};
}
// Get the content for each blog post
export async function getStaticProps({ params }) {
const { data, error } = await nextBlogAI.getBlogPost(params.slug);
if (error || !data) {
return { notFound: true };
}
return {
props: {
post: data,
},
// Optionally revalidate the page after a certain time
revalidate: 3600, // 1 hour
};
}
// Your component to render the blog post
function BlogPost({ post }) {
// Render the post content
}
export default BlogPost;
For the App Router in Next.js with static exports, use the generateStaticParams
function:
// app/blog/[slug]/page.tsx
import { createNextBlogAIForNextJs } from 'next-blog-ai';
const { getAllBlogSlugs, getBlogPost } = createNextBlogAIForNextJs(
process.env.NEXT_BLOG_AI_API_KEY!
);
// Generate static paths at build time
export async function generateStaticParams() {
const { data, error } = await getAllBlogSlugs();
if (error || !data) {
return [];
}
return data.slugs.map((slug) => ({ slug }));
}
// Server Component to render the blog post
export default async function BlogPostPage({
params,
}: {
params: { slug: string };
}) {
const { slug } = params;
const { data, error } = await getBlogPost(slug);
if (error || !data) {
return <div>Blog post not found</div>;
}
return (
<>
{/* Render blog post content */}
{data.format === 'html' ? (
<div dangerouslySetInnerHTML={{ __html: data.content }} />
) : (
<>
<h1>{data.post.title}</h1>
<div>{data.post.content}</div>
</>
)}
</>
);
}
This approach allows you to pre-render all your blog posts at build time, improving performance and SEO.
Next-Blog-AI supports two display formats for blog listings when using the HTML format:
The grid view displays blog posts in a responsive grid layout, which is ideal for blog homepages or archive pages where you want to showcase multiple posts in a compact, visually appealing format.
const { data } = await nextBlogAI.getBlogPosts({
display: 'grid', // This is the default value
});
The list view displays blog posts in a vertical list, with a horizontal layout for each post card. This view is ideal for readers who prefer a more traditional blog layout or when you want to emphasize the content hierarchy.
const { data } = await nextBlogAI.getBlogPosts({
display: 'list',
});
You can also set the default display format when initializing the client:
const nextBlogAI = createNextBlogAI({
apiKey: 'your-api-key',
defaultBlogListDisplay: 'list', // Sets the default to list view
});
Note: The display format option only applies when using the HTML format. When using the JSON format, you'll need to implement your own display logic using the returned data.
By default, Next-Blog-AI has caching disabled to ensure you always get fresh content during development. This behavior can be customized:
You can enable caching by:
// For individual requests
const { data } = await getBlogPosts({
next: {
revalidate: 3600, // Cache for 1 hour
},
});
// Or set a default when creating the client
const { getBlogPosts } = createNextBlogAIForNextJs(
process.env.NEXT_BLOG_AI_API_KEY!,
{ revalidate: 3600 } // Default to caching for 1 hour
);
Caching is disabled by default, but you can explicitly disable it:
const { data } = await getBlogPosts({
next: {
revalidate: 0, // Disable cache for this request
// or
dynamic: true, // Also disables cache
},
});
If you're using Next.js App Router with the standard createNextBlogAI
function (not the Next.js wrapper), you can directly specify fetch options to control caching:
// Force dynamic rendering (no caching)
const { data } = await nextBlogAI.getBlogPosts({
cache: {
fetchOptions: {
cache: 'no-store', // Force dynamic rendering
},
},
});
// Or use incremental static regeneration
const { data } = await nextBlogAI.getBlogPosts({
cache: {
fetchOptions: {
next: {
revalidate: 3600, // Revalidate every hour
},
},
},
});
By default, when using createNextBlogAI()
with Next.js App Router, the client will use dynamic rendering with cache: 'no-store'
for all requests to ensure you always get fresh content.
You can customize these defaults when creating the client:
// Override the default fetch options (which is 'no-store')
const nextBlogAI = createNextBlogAI({
apiKey: 'your-api-key',
defaultFetchOptions: {
cache: 'force-cache',
next: {
revalidate: 3600, // Use ISR with 1 hour revalidation instead
},
},
});
// All requests will now use these custom fetch options
const { data } = await nextBlogAI.getBlogPosts();
Individual request options will override the defaults:
// This specific request will use these options instead of the defaults
const { data } = await nextBlogAI.getBlogPosts({
cache: {
fetchOptions: {
cache: 'no-store', // Override back to dynamic rendering
},
},
});
When integrating Next-Blog-AI into your Next.js project, consider the following structure:
src/
lib/
next-blog-ai.ts // Client initialization
app/
blog/
page.tsx // Blog listing
[slug]/
page.tsx // Blog post detail
opengraph-image.tsx // OG image generation
api/
blog/
comment/
route.ts // Server action for comments
Set up your environment variables in a .env.local
file:
NEXT_BLOG_AI_API_KEY=your_api_key_here