Blog
March 25, 2025

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

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

Yassine Zaanouni
Yassine Zaanouni
5 mins read

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

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

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

Step 1: Setting Up Your Scalar Project

Let's start by configuring our content models in Scalar.

Creating a New Project

  1. Log in to your Scalar 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 Scalar Schema Editor
type Author = {
  name: string;
  bio: RichText;
  avatar: Media;
  socialLinks?: {
    twitter?: string;
    github?: string;
    linkedin?: string;
  };
};

Blog Post Model

// In Scalar 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 Scalar SDK and other dependencies
npm install @scalar/api-client date-fns reading-time

Step 3: Connecting to Scalar

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:

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 Scalar'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
vercel

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

Conclusion

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