January 15, 2025

How to Build a Modern Website with Next.js and Sanity.io

Create a modern, dynamic, and SEO-friendly blog by combining Next.js with Sanity.io. Next.js provides fast performance with features like server-side rendering (SSR) and static site generation (SSG), while Sanity.io serves as a flexible, real-time headless CMS. This stack ensures scalability, real-time content updates, and an optimized user experience, making it perfect for modern blogs. πŸš€

How to Build a Modern Website with Next.js and Sanity.io
πŸ‘‹πŸŒ

In today’s fast-paced web development world, creating a dynamic, fast, and SEO-friendly blog has never been easier. Combining Next.js, a powerful React-based framework, with Sanity.io, a flexible and highly customizable headless CMS, gives developers the perfect toolkit for building modern blogs. Let’s dive into the process step by step!


Why Choose Next.js and Sanity.io?

Next.js

  1. Server-Side Rendering (SSR) and Static Site Generation (SSG): Optimizes performance and SEO.
  2. API Routes: Easily create custom API endpoints.
  3. Built-in Image Optimization: Automatically optimizes images for better performance.
  4. File-based Routing: Simple and intuitive routing system.

Sanity.io

  1. Real-Time Content Updates: Live content editing with collaborative features.
  2. Customizable Schema: Build exactly what you need with flexible content models.
  3. Portable Text: Handle rich text with ease.
  4. Sanity Studio: A headless CMS you can self-host or use via their managed cloud.

Steps to Build a Blog with Next.js and Sanity.io

1. Set Up Your Next.js Project

Start by initializing a new Next.js project:

npx create-next-app@latest blog-nextjs-sanity
cd blog-nextjs-sanity

Install the necessary dependencies:

npm install @sanity/client @sanity/image-url react-portable-text

2. Create a Sanity.io Project

  • Head over to Sanity.io.
  • Create a new project and choose the Blog Template for a head start.
  • Install Sanity CLI globally:
    npm install -g @sanity/cli
  • Set up the Sanity Studio locally:
    sanity init
    During initialization, configure your project settings like dataset (default: production).

3. Define Your Content Schema

In the schemas folder of your Sanity Studio, customize the default schema or create your own. For example:

// schemas/post.js
export default {
  name: "post",
  title: "Post",
  type: "document",
  fields: [
    {
      name: "title",
      title: "Title",
      type: "string",
    },
    {
      name: "slug",
      title: "Slug",
      type: "slug",
      options: {
        source: "title",
        maxLength: 96,
      },
    },
    {
      name: "mainImage",
      title: "Main Image",
      type: "image",
      options: {
        hotspot: true,
      },
    },
    {
      name: "body",
      title: "Body",
      type: "array",
      of: [{ type: "block" }],
    },
    {
      name: "publishedAt",
      title: "Published At",
      type: "datetime",
    },
  ],
};

Deploy your changes:

sanity deploy

4. Connect Next.js to Sanity.io

Create a Sanity client to fetch data from your CMS. In your project root, create a file named sanity.js:

import { createClient } from '@sanity/client';
import imageUrlBuilder from '@sanity/image-url';
 
export const client = createClient({
  projectId: 'your-project-id',
  dataset: 'production',
  apiVersion: '2023-01-01',
  useCdn: true,
});
 
const builder = imageUrlBuilder(client);
export const urlFor = (source) => builder.image(source);

5. Fetch Blog Posts

In pages/index.js, fetch your blog posts using getStaticProps:

import { client } from "../sanity";
import Link from "next/link";
 
export default function Home({ posts }) {
  return (
    <div className="container mx-auto p-5">
      <h1 className="text-4xl font-bold mb-6">My Blog</h1>
      <ul>
        {posts.map((post) => (
          <li key={post._id}>
            <Link href={`/post/${post.slug.current}`}>
              <a className="text-blue-500">{post.title}</a>
            </Link>
          </li>
        ))}
      </ul>
    </div>
  );
}
 
export async function getStaticProps() {
  const query = `*[_type == "post"]{
    _id,
    title,
    slug
  }`;
  const posts = await client.fetch(query);
  return { props: { posts } };
}

6. Build a Single Post Page

In pages/post/[slug].js:

import { client, urlFor } from "../../sanity";
import { PortableText } from "react-portable-text";
 
export default function Post({ post }) {
  return (
    <div className="container mx-auto p-5">
      <h1 className="text-4xl font-bold">{post.title}</h1>
      <img
        src={urlFor(post.mainImage).url()}
        alt={post.title}
        className="my-5"
      />
      <PortableText
        content={post.body}
        serializers={{
          h1: (props) => <h1 className="text-2xl font-bold" {...props} />,
          li: ({ children }) => <li className="ml-4 list-disc">{children}</li>,
        }}
      />
    </div>
  );
}
 
export async function getStaticPaths() {
  const query = `*[_type == "post"]{ slug { current } }`;
  const posts = await client.fetch(query);
 
  const paths = posts.map((post) => ({
    params: { slug: post.slug.current },
  }));
 
  return { paths, fallback: 'blocking' };
}
 
export async function getStaticProps({ params }) {
  const query = `*[_type == "post" && slug.current == $slug][0]`;
  const post = await client.fetch(query, { slug: params.slug });
 
  return { props: { post } };
}

7. Add Styling

Use Tailwind CSS for a clean and responsive UI. Install Tailwind:

npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init

Configure Tailwind by updating tailwind.config.js:

module.exports = {
  content: ["./pages/**/*.{js,ts,jsx,tsx}", "./components/**/*.{js,ts,jsx,tsx}"],
  theme: {
    extend: {},
  },
  plugins: [],
};

Add Tailwind directives in styles/globals.css:

@tailwind base;
@tailwind components;
@tailwind utilities;

Final Thoughts

Combining Next.js and Sanity.io allows you to build a powerful, scalable, and highly customizable blog. With real-time content editing and SEO-friendly features, this stack is perfect for modern blogging needs.

You can take this further by:

  • Adding categories and tags.
  • Implementing advanced features like search or pagination.
  • Hosting your project on platforms like Vercel for seamless deployment.

Happy coding! πŸš€


Popular blogs