Blog
March 25, 2025

Building a blog with Crawler, Next.js, and Tailwind

Follow this step-by-step guide to launch a performant, developer-friendly blog using Crawler and your favorite tools.

Yassine Zaanouni
Yassine Zaanouni
5 mins read

Building a blog with Crawler, Next.js, and Tailwind

Follow this step-by-step guide to launch a performant, developer-friendly blog using Crawler 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:

  • Crawler 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 Crawler account (free tier works fine)
  • Basic familiarity with React and Next.js
  • Git for version control

Step 1: Setting Up Your Crawler Project

Let’s start by configuring our content models in Crawler.

Creating a New Project

  1. Log in to your Crawler account
  2. Create a new project named “Next.js Blog”
  3. Choose the blank template

Defining Content Models

We’ll create two main content types: Author and BlogPost.

Author Model

// In Crawler Schema Editor
type Author = {
name: string;
bio: RichText;
avatar: Media;
socialLinks?: {
twitter?: string;
github?: string;
linkedin?: string;
};
};

Blog Post Model

// In Crawler 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.

Terminal window
# 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 Crawler SDK and other dependencies
npm install @scalar/api-client date-fns reading-time

Step 3: Connecting to Crawler

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 here

Step 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:

Terminal window
npm install @scalar/rich-text-react

Use 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 Crawler’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:

Terminal window
npm install -g vercel
vercel

Make sure to add your Crawler environment variables in the Vercel dashboard.

Conclusion

You now have a fully functioning blog powered by Crawler, 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. Crawler 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 Crawler or join us on Discord .