Blog System

MDX-based blog with syntax highlighting, SEO optimization, and static generation.

Content

  • • MDX for rich markdown
  • • Code syntax highlighting
  • • Custom React components
  • • Reading time estimation

SEO

  • • Automatic meta tags
  • • Open Graph images
  • • JSON-LD structured data
  • • Static generation (SSG)

Structure

src/content/blog/
├── getting-started.mdx
├── feature-update.mdx
└── welcome.mdx
src/app/blog/
├── page.tsx # Blog listing
└── [slug]/
└── page.tsx # Individual post

Post Template

src/content/blog/getting-started.mdx
1---
2title: "Getting Started"
3description: "Learn how to build your SaaS."
4date: "2024-03-15"
5author: "Your Name"
6category: "tutorial"
7tags: ["nextjs", "saas"]
8featured: true
9---
10
11# Getting Started
12
13Welcome! This guide helps you get up and running.
14
15## Step 1: Clone the Repository
16
17```bash
18git clone https://github.com/your-repo.git
19cd your-repo
20pnpm install
21```

Utilities

src/lib/mdx.ts
1import fs from 'fs';
2import path from 'path';
3import matter from 'gray-matter';
4
5const BLOG_PATH = path.join(process.cwd(), 'src/content/blog');
6
7export function getAllBlogPosts() {
8 const files = fs.readdirSync(BLOG_PATH);
9
10 return files
11 .filter(file => file.endsWith('.mdx'))
12 .map(file => {
13 const { data, content } = matter(
14 fs.readFileSync(path.join(BLOG_PATH, file), 'utf8')
15 );
16 return {
17 slug: file.replace('.mdx', ''),
18 ...data,
19 readingTime: Math.ceil(content.split(/\s+/).length / 200),
20 };
21 })
22 .sort((a, b) => new Date(b.date) - new Date(a.date));
23}

Post Page

src/app/blog/[slug]/page.tsx
1import { notFound } from "next/navigation";
2import { getBlogPost, getAllBlogPosts } from "~/lib/mdx";
3
4export async function generateStaticParams() {
5 return getAllBlogPosts().map(post => ({ slug: post.slug }));
6}
7
8export async function generateMetadata({ params }) {
9 const post = getBlogPost(params.slug);
10 if (!post) return {};
11 return {
12 title: post.title,
13 description: post.description,
14 openGraph: { type: "article", publishedTime: post.date },
15 };
16}
17
18export default async function BlogPostPage({ params }) {
19 const post = getBlogPost(params.slug);
20 if (!post) notFound();
21
22 return (
23 <article className="prose dark:prose-invert">
24 <h1>{post.title}</h1>
25 {/* MDX content */}
26 </article>
27 );
28}

Content Tips

Writing

  • • Write compelling headlines
  • • Use clear, scannable structure
  • • Include code examples
  • • Add helpful images

Strategy

  • • Document product features
  • • Share industry insights
  • • Create tutorials
  • • Answer common questions

Next: Waitlist

Pre-launch email collection

Continue →