Home
Work
Blog

Building my personal blog with Sanity CMS

Published on: 05/25/2024

Sanity CMS Logo

tldr;

I recently decided to overhaul my personal website, and while doing it I realized I wanted to start doing some blog posts here. Instead of using something static that I would check into my GitHub repo, I decided to learn how to use a headless CMS. After super minimal investigation into what's available, I chose Sanity.

This is not a step-by-step on how to do this. Just my motivations, experience, and learnings.

How I built my site

My site is a Next.js app hosted on Vercel. I used the new App Router because I'm personally a fan of the new routing and composable layouts. I'm also using 100% typescript, React Server Components, and static site generation.

Deciding to blog

This is something that I've been wanting to do for some time now. I've written a couple articles during college on Medium, but didn't keep up with it.

I'm also a software engineer and love to learn new things, so I thought I'd look into some popular headless content management systems (CMS) to build it. This is definitely not necessary but sounded like fun to me.

What is Sanity and why use it

From their homepage (sanity.io):

Sanity delivers content anywhere (just like a headless CMS). Beyond that, Sanity gives you total composability. A fully decoupled, real-time content back end. Entirely customizable content workspaces.

Basically, it's a headless CMS that:

I didn't do any fancy evaluation to choose Sanity. I just wanted something really developer friendly.

Setting up Sanity in a Next.js app

Here's the article I followed to integrate Sanity into my site: https://www.sanity.io/blog/build-your-own-blog-with-sanity-and-next-js. I didn't follow this exactly. I used it for some initial guidance on getting started with Sanity and Next.js. Below are some highlights on the process.

Integration into Next.js was easy

I just ran an npm command and it led me through authentication and choosing a content model. There's already a "Blog" template with schemas for a Post, Author, and Category.

The initial step set up the schema and integrated a "studio". This is basically an entire web app hosted directly on your site under a route that you specify.

Sanity studio

I used the route groups feature of the new app router to keep my studio route separate from my actual website pages so that none of the layouts are shared.

Displaying blog posts

To actually fetch blog data, I used Sanity's Javascript client @sanity/client which. However, this takes raw queries and returns "any". I was not a fan. Luckily Sanity has a CLI with a beta type generation feature. This let me add concrete types to my queries.

Typed Sanity query

For the actual pages, I created two file paths. One to list out all my blog posts and one to display a single blog post.

Routes

For the first, I have a query that queries all my posts sorted by published date in descending order. I use this in a React Server Component to display them as a list of links.

For the second (single post), I have a query that fetches all the slugs. I use this in the generateStaticParams at the page level to prerender all my posts at build-time. I have another query that fetches the actual blog post and I use that data in another React Server Component to render the post.

Most of the fields on my Blog model are primitives, but the actual blog body is a spec called PortableText. There's a library that is able to convert this data into React JSX called portabletext/react-portabletext. The nice part here is that it also let's us create a mapping of elements to our own styled elements.

Custom components

For the typography on my site I'm using shadcn, so it was extremely nice to be able to keep the styles and typography consistent throughout my site and blog.

Automated deploys

After I set everything up and was able to properly render some posts, I wanted to be able to just go to the Sanity studio and create a post that would trigger a static rebuild of my website.

I exposed a deploy hook on my Vercel project for this site, and then entered it into Sanity. Any time that data is updated in Sanity, my site will rebuild and redeploy with all the content prerendered 🎉

Check out my code

My whole site is public at github.com/amanzanero/amanzanero.com. Feel free to dig into it yourself!