Building a blog with Wendy, Next.js, and Tailwind
Follow this step-by-step guide to launch a performant, developer-friendly blog using Wendy and your favorite tools.
Building a blog with Wendy, Next.js, and Tailwind
Follow this step-by-step guide to launch a performant, developer-friendly blog using Wendy and your favorite tools.
The Perfect Tech Stack for Modern Blogs
Blogs remain one of the most effective ways to share knowledge, build authority, and connect with your audience. But today's readers expect fast, responsive, and visually appealing blog experiences.
In this tutorial, we'll build a high-performance blog using three powerful technologies:
- Wendy for flexible content management
- Next.js for fast, SEO-friendly rendering
- Tailwind CSS for beautiful, responsive designs
This combination gives you the benefits of a headless CMS approach (content flexibility, developer experience, performance) without sacrificing the ease of use content creators expect.
Prerequisites
Before we start, make sure you have:
- Node.js 18+ installed
- A Wendy account (free tier works fine)
- Basic familiarity with React and Next.js
- Git for version control
Step 1: Setting Up Your Wendy Project
Let's start by configuring our content models in Wendy.
Creating a New Project
- Log in to your Wendy account
- Create a new project named "Next.js Blog"
- Choose the blank template
Defining Content Models
We'll create two main content types: Author and BlogPost.
Author Model
// In Wendy Schema Editor
type Author = {
name: string;
bio: RichText;
avatar: Media;
socialLinks?: {
twitter?: string;
github?: string;
linkedin?: string;
};
};Blog Post Model
// In Wendy Schema Editor
type BlogPost = {
title: string;
slug: string;
summary: string;
content: RichText;
coverImage: Media;
publishedDate: Date;
featured: boolean;
author: Reference<Author>;
tags: string[];
seo?: {
title?: string;
description?: string;
keywords?: string[];
};
};Adding Sample Content
Before we move to the frontend, let's add:
- At least one author
- 3-5 blog posts with varied content
Step 2: Creating Your Next.js Project
Now let's set up our frontend application.
# Create a new Next.js project
npx create-next-app@latest my-scalar-blog --typescript --tailwind --app
# Navigate to your project
cd my-scalar-blog
# Install Wendy SDK and other dependencies
npm install @scalar/api-client date-fns reading-timeStep 3: Connecting to Wendy
Create a new file at lib/scalar.ts:
import { createClient } from '@scalar/api-client';
export const scalarClient = createClient({
projectId: process.env.SCALAR_PROJECT_ID!,
apiKey: process.env.SCALAR_API_KEY!,
});
export async function getBlogPosts({
featured,
limit,
}: {
featured?: boolean;
limit?: number;
} = {}) {
const query: any = {};
if (featured !== undefined) {
query.featured = featured;
}
const posts = await scalarClient.getBlogPosts({
query,
sort: { publishedDate: 'desc' },
limit,
include: ['author'],
});
return posts;
}
export async function getBlogPostBySlug(slug: string) {
const posts = await scalarClient.getBlogPosts({
query: { slug },
limit: 1,
include: ['author'],
});
return posts[0] || null;
}Create a .env.local file:
SCALAR_PROJECT_ID=your-project-id
SCALAR_API_KEY=your-api-key
Step 4: Building the Blog Homepage
Create app/page.tsx:
import Link from 'next/link';
import Image from 'next/image';
import { getBlogPosts } from '@/lib/scalar';
export default async function HomePage() {
const posts = await getBlogPosts({ limit: 10 });
const featuredPost = posts.find((post) => post.featured);
const regularPosts = posts.filter((post) => !post.featured);
return (
<main className="mx-auto max-w-5xl px-4 py-12">
<h1 className="mb-12 text-4xl font-bold">My Blog</h1>
{featuredPost && (
<div className="mb-16">
<h2 className="mb-4 text-2xl font-bold">Featured</h2>
<FeaturedPostCard post={featuredPost} />
</div>
)}
<div className="grid grid-cols-1 gap-8 md:grid-cols-2">
{regularPosts.map((post) => (
<PostCard key={post.id} post={post} />
))}
</div>
</main>
);
}
// Add FeaturedPostCard and PostCard components hereStep 5: Creating the Blog Post Page
Create app/blog/[slug]/page.tsx:
import Image from 'next/image';
import { notFound } from 'next/navigation';
import { getBlogPostBySlug } from '@/lib/scalar';
import { formatDate } from '@/lib/utils';
export default async function BlogPostPage({
params,
}: {
params: { slug: string };
}) {
const post = await getBlogPostBySlug(params.slug);
if (!post) {
notFound();
}
return (
<article className="mx-auto max-w-3xl px-4 py-12">
<h1 className="mb-4 text-4xl font-bold">{post.title}</h1>
<div className="mb-8 flex items-center">
<Image
src={post.author.avatar.url}
alt={post.author.name}
width={40}
height={40}
className="mr-4 rounded-full"
/>
<div>
<p className="font-medium">{post.author.name}</p>
<p className="text-sm text-gray-500">
{formatDate(post.publishedDate)}
</p>
</div>
</div>
<Image
src={post.coverImage.url}
alt={post.title}
width={900}
height={500}
className="mb-8 rounded-lg"
/>
<div className="prose lg:prose-lg">
{/* Render your rich text content here */}
{post.content}
</div>
</article>
);
}Step 6: Adding Navigation and Layout
Create or modify app/layout.tsx:
import './globals.css';
import Link from 'next/link';
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
<header className="border-b">
<div className="mx-auto flex max-w-5xl items-center justify-between px-4 py-6">
<Link href="/" className="text-2xl font-bold">
My Blog
</Link>
<nav>
<ul className="flex gap-6">
<li>
<Link href="/">Home</Link>
</li>
<li>
<Link href="/about">About</Link>
</li>
<li>
<Link href="/contact">Contact</Link>
</li>
</ul>
</nav>
</div>
</header>
{children}
<footer className="mt-12 border-t">
<div className="mx-auto max-w-5xl px-4 py-8 text-center text-gray-500">
© {new Date().getFullYear()} My Blog. All rights reserved.
</div>
</footer>
</body>
</html>
);
}Step 7: Enhancing Your Blog
To take your blog to the next level, consider these enhancements:
Adding a Rich Text Renderer
Install a package to render your rich text content:
npm install @scalar/rich-text-reactUse it in your blog post page.
Implementing Tags and Categories
Create tag and category pages to organize your content.
Adding Search Functionality
Implement search using Wendy's filtering capabilities.
Setting up Analytics
Add a web analytics tool to track visitor engagement.
Deployment
The simplest way to deploy your Next.js blog is with Vercel:
npm install -g vercel
vercelMake sure to add your Wendy environment variables in the Vercel dashboard.
Conclusion
You now have a fully functioning blog powered by Wendy, Next.js, and Tailwind CSS. This stack gives you:
- A clean, type-safe content API
- Blazing fast page loads with SSR and static generation
- Beautiful responsive design
- Great developer experience
From here, you can continue customizing your blog with additional features, design tweaks, and content strategy.
Wrap-up
A CMS shouldn't slow you down. Wendy aims to expand into your workflow — whether you're coding content models, collaborating on product copy, or launching updates at 2am.
If that sounds like the kind of tooling you want to use — try Wendy or join us on Discord.