How to Serialize Code Snippets and Image in Sanity V3 and NextJS

Updated at: 22 July 2023Deepak Painkra

In this article, I will show you how to add code blocks and images to your latest Sanity v3 studio and NextJS 13 project. Just adding a code block and images is simple, but when it comes to showing them in the frontend app, it is a bit tricky, so bear with me, and I will show you how to do it by yourself.

I'm assuming that you have already created your sanity project, and if not, then start your project by issuing this command,

npm create sanity@latest -- --template clean --create-project "Sanity Project" --dataset production

Choose the dataset name that will be production, and in case you want to give it a name, then you can give it a name,

  • No TypeScript
  • Blog Schema Yes

Next Steps we need to add this plugin to show code blocks, so issue this command into the terminal,

npm i @sanity/code-input

Now add this plugin to the sanity.config.js

import {codeInput} from '@sanity/code-input'

export default defineConfig({
  // ...
  plugins: [codeInput()],
})

Also, we need to mention this plugin in the blockContent.js

 {
      type: 'code',     
 }
and make sure to run this command after making these changes,

npm run build

Frontend Part

Now let's create our next app by issuing this command,

npx create-next-app@latest

I'm not using the app router because the app router is not compatible with most of the libraries.

  • No TypeScript
  • No App Router

And in case you're using an app directory, then the process will be the same.

To be able to render images from sanity, we need to mention this thing in the next.config.js

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,

  images: { domains: ['cdn.sanity.io'] }

}

module.exports = nextConfig

Next steps, to show images, we need to install this package,

npm install --save @sanity/image-url

Write this code into the blog.js file,

import { useRouter } from 'next/router'
import Head from 'next/head'
import SyntaxHighlighter from 'react-syntax-highlighter';
import Image from 'next/image';
import imageUrlBuilder from '@sanity/image-url'
import { createClient } from "next-sanity";
import React from 'react'
const BlockContent = require('@sanity/block-content-to-react')

const Post = ({ post, profile }) => {
  const router = useRouter()

  const client = createClient({
    projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID,
    dataset: process.env.NEXT_PUBLIC_SANITY_DATASET,
    apiVersion: process.env.NEXT_PUBLIC_SANITY_API_VERSION,
    useCdn: false
  });
  const builder = imageUrlBuilder(client)

  function urlFor(source) {
    return builder.image(source)
  }
  const serializers = {
    types: {
      code: (props) => (
        <SyntaxHighlighter language={props.node.language} >
          {props.node.code}
        </SyntaxHighlighter>
      ),
    },
  };

  return (

    <div>
      {post?.mainImage ? <Image
        src={builder.image(post.mainImage).width(300).height(300).url()}
        width={600}
        height={300}
        alt={post?.mainImage?.alt}
      /> : null}

      <h1>{post.title}</h1>
      <small>{profile?.author}</small>
      <BlockContent
        blocks={post.body}
        projectId={process.env.NEXT_PUBLIC_SANITY_PROJECT_ID}
        dataset={process.env.NEXT_PUBLIC_SANITY_DATASET}
        serializers={serializers}
      />
    </div>
  )
}

export default Post

export const getServerSideProps = async (context) => {
  const { slug } = context.query
  const client = createClient({
    projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID,
    dataset: process.env.NEXT_PUBLIC_SANITY_DATASET,
    apiVersion: process.env.NEXT_PUBLIC_SANITY_API_VERSION,
    useCdn: false
  });
  const query = `*[_type == "post" && slug.current == '${slug}'][0]`;
  const post = await client.fetch(query);

  return {
    props: {
      post,
    }
  }
}

do not forget to set your environment variable into the .env file,

We need to import the blockContent from sanity, and in case you're using portable text, it will not render code snippets, so it's better to use blockContent instead,