Xw3qBlog logoXw3qBlog

← Back to Home

Building a Blog with Next.js and Sanity: A Complete Step-by-Step Guide

23 views·Like (0)·0 comments

Next.js and Sanity form a powerful combination for modern content-driven websites. Next.js provides a fast React-based frontend framework with server-side rendering and static generation capabilities, while Sanity offers a flexible headless CMS that allows content editors to manage content without touching code. In this tutorial, we will build a simple blog application from scratch, covering project setup, Sanity configuration, content schemas, data fetching, dynamic routes, and deployment-ready code examples.


Building a Blog with Next.js and Sanity: A Complete Step-by-Step Guide

Modern websites often require a clean separation between content management and frontend presentation. This is where a headless CMS shines.

One of the most popular stacks today combines:

  • Next.js for the frontend
  • Sanity CMS for content management

This setup allows developers to build highly performant websites while giving content editors a user-friendly interface to manage content.

In this tutorial, we'll build a simple blog using Next.js App Router and Sanity CMS.

---

Prerequisites

Before starting, ensure you have:

  • Node.js 20+
  • npm or pnpm
  • A Sanity account
  • Basic React knowledge

---

Step 1: Create a Next.js Project

Create a new Next.js application.

npx create-next-app@latest nextjs-sanity-demo

cd nextjs-sanity-demo

Recommended options:

✔ TypeScript: Yes
✔ ESLint: Yes
✔ Tailwind CSS: Yes
✔ App Router: Yes
✔ src directory: Yes

Start the development server:

npm run dev

Visit:

http://localhost:3000

---

Step 2: Create a Sanity Project

Install Sanity CLI:

npm create sanity@latest

Follow the prompts:

Project Name: blog-cms
Dataset: production
Template: Clean project

After completion:

cd blog-cms
npm run dev

Sanity Studio will be available at:

http://localhost:3333

---

Step 3: Create a Post Schema

Inside:

sanity/schemaTypes

Create:

// post.ts

import {defineField, defineType} from 'sanity'

export default defineType({
  name: 'post',
  title: 'Post',
  type: 'document',
  fields: [
    defineField({
      name: 'title',
      title: 'Title',
      type: 'string'
    }),
    defineField({
      name: 'slug',
      title: 'Slug',
      type: 'slug',
      options: {
        source: 'title'
      }
    }),
    defineField({
      name: 'excerpt',
      title: 'Excerpt',
      type: 'text'
    }),
    defineField({
      name: 'content',
      title: 'Content',
      type: 'array',
      of: [{type: 'block'}]
    })
  ]
})

Register the schema:

// schema.ts

import post from './post'

export const schemaTypes = [post]

Restart Studio.

You can now create blog posts from the Sanity dashboard.

---

Step 4: Install Sanity Client in Next.js

Back in the Next.js project:

npm install next-sanity

Create:

src/lib/sanity.ts
import { createClient } from 'next-sanity'

export const client = createClient({
  projectId: 'YOUR_PROJECT_ID',
  dataset: 'production',
  apiVersion: '2025-01-01',
  useCdn: false
})

Find your project ID in:

Sanity Dashboard → API

---

Step 5: Create GROQ Queries

Create:

src/lib/queries.ts
export const POSTS_QUERY = `
*[_type == "post"]{
  _id,
  title,
  slug,
  excerpt
}
`

Single post query:

export const POST_QUERY = `
*[_type == "post" && slug.current == $slug][0]
`

---

Step 6: Fetch Posts on Homepage

Replace:

src/app/page.tsx

with:

import Link from 'next/link'
import { client } from '@/lib/sanity'
import { POSTS_QUERY } from '@/lib/queries'

export default async function Home() {

  const posts = await client.fetch(POSTS_QUERY)

  return (
    <main className="max-w-4xl mx-auto p-8">
      <h1 className="text-4xl font-bold mb-8">
        Blog
      </h1>

      {posts.map((post:any) => (
        <article key={post._id} className="mb-6">
          <Link
            href={`/posts/${post.slug.current}`}
          >
            <h2 className="text-2xl font-semibold">
              {post.title}
            </h2>
          </Link>

          <p>{post.excerpt}</p>
        </article>
      ))}
    </main>
  )
}

---

Step 7: Create Dynamic Post Pages

Create:

src/app/posts/[slug]/page.tsx
import { client } from '@/lib/sanity'
import { POST_QUERY } from '@/lib/queries'

export default async function PostPage({
  params
}:{
  params:{slug:string}
}) {

  const post = await client.fetch(
    POST_QUERY,
    { slug: params.slug }
  )

  return (
    <article className="max-w-3xl mx-auto p-8">
      <h1 className="text-4xl font-bold mb-4">
        {post.title}
      </h1>

      <p>{post.excerpt}</p>
    </article>
  )
}

Now each blog post has its own route:

/posts/my-first-post

---

Step 8: Render Rich Text Content

Install:

npm install @portabletext/react

Update:

import { PortableText } from '@portabletext/react'

<PortableText value={post.content} />

Full example:

<article>
  <h1>{post.title}</h1>

  <PortableText
    value={post.content}
  />
</article>

This renders rich text created in Sanity Studio.

---

Step 9: Environment Variables

Create:

.env.local
NEXT_PUBLIC_SANITY_PROJECT_ID=xxxxx

NEXT_PUBLIC_SANITY_DATASET=production

Update client:

export const client = createClient({
  projectId:
    process.env.NEXT_PUBLIC_SANITY_PROJECT_ID!,
  dataset:
    process.env.NEXT_PUBLIC_SANITY_DATASET!,
  apiVersion: '2025-01-01',
  useCdn: false
})

Never hardcode project credentials.

---

Step 10: Deploy to Vercel

Push code:

git init

git add .

git commit -m "Initial commit"

Create repository:

GitHub

Import project into Vercel.

Add environment variables.

Deploy.

Your stack becomes:

Frontend:
Next.js (Vercel)

CMS:
Sanity Studio

Content API:
Sanity Content Lake

---

Final Project Structure

src
├── app
│   ├── page.tsx
│   └── posts
│       └── [slug]
│           └── page.tsx
│
├── lib
│   ├── sanity.ts
│   └── queries.ts

sanity
├── schemaTypes
│   └── post.ts

---

Why This Stack Is Popular

The Next.js + Sanity combination has become a favorite among startups, agencies, and content-driven businesses because it offers:

  • Fast page performance
  • Flexible content modeling
  • Excellent SEO support
  • Real-time content updates
  • Easy deployment on Vercel
  • Strong TypeScript support
  • Scalability from small blogs to enterprise applications

For developers building blogs, documentation sites, company websites, educational platforms, or content-heavy SaaS products, Next.js and Sanity provide a modern and highly productive development experience.

About petercontinue

peter love study

Comments

Sign in to leave a comment.

  • No comments yet. Be the first to comment.