HS
  • Home
  • About
  • Projects
  • Blog ↗
  • Contact
© 2026 Hemant Singh
HS
© 2026 Hemant Singh Poonia. Built with technical precision.
LinkedInGitHub𝕏Email

My Introduction to Content Management using Next.js and Sanity

Hemant Singh Poonia•June 28, 2026•10 min read
cover image - my introduction to content management

I recently built my portfolio site, and while figuring out the design and what content to put on it, an idea struck me: I wanted to include a blog. Not the daily-journal kind, but a place to write about the technical things I learn during my coding sessions, reading docs, picking up new libraries, and so on.

Coding is something that really fascinates me. So instead of going with the first solution I find on the internet or get from an LLM, I usually go round and round, trying out different approaches, just to understand the pros and cons of each before picking the one that fits what I actually need. This blog post is about one of those detours, the one I took while setting up the blogging system itself.

Why I didn't just use Markdown files

The trending way to add a blog to a Next.js portfolio is pretty simple: write your posts as MDX files (which support React components too), drop them into a folder in your source code, and let Next.js generate the pages with a bit of boilerplate. It's fast, it gives you statically generated pages, and it's great for SEO.

I knew all this. I still didn't go that route. You might ask why, since engineering is supposed to be about finding the most efficient solution, and this clearly was one. Fair question. I had two reasons, and neither of them was really a "problem" with the MDX approach so much as a deliberate detour I chose to take:

  1. I wanted to actually understand how content management works today. I wasn't going to build an enterprise-grade system, but I figured this was a good excuse to learn the different approaches individuals and companies use to deliver content.
  2. I push all my meaningful code to GitHub, and I didn't want my commit history to fill up with "added new blog post" commits instead of actual code.

What I learned about content management

These days, my first move for any unfamiliar problem is to ask an LLM, then go deep on the actual docs. So once I'd decided I wanted a blog but didn't want to touch source code to publish a post, I went to Gemini and asked what I should be doing.

I already had a rough idea of what CMS platforms were, and since I was using Next.js, I knew there'd be some way to pre-render pages statically. That mattered to me for two reasons: my blog posts are just write-ups of technical things I've learned, so they're static content by nature, and rendering them on every request would be wasteful, and It would also be bad for SEO.

What I didn't know was how CMS platforms actually worked under the hood, whether a headless CMS was the only sensible option, or how Incremental Static Regeneration (ISR) and revalidation worked in Next.js, since I'd never touched that part of the framework before.

Gemini told me what I needed was a "headless CMS + ISR" setup. I asked it to explain how that would actually work, and the answer was roughly this: I'd write content in a text editor on a separate portal (which could also be hosted on my own site), and once I hit "publish," a webhook on my site would catch the new content. From there, Next.js would handle the SSG + ISR side of things, regenerating the static pages without me ever touching my source code.
Then it suggested something else: since I clearly wanted to learn this deeply, why not build my own headless CMS? It even offered to help.

By now, most people have learned not to take an LLM's suggestion at face value, and after sitting with the idea for a bit, building my own headless CMS stopped making sense, for a few reasons:

  1. There are already excellent headless CMS platforms with generous free tiers for solo writers like me.
  2. A big chunk of building a CMS is building a text editor, and that felt like reinventing the wheel. There are already far better editors out there, and building my own wouldn't teach me much relative to the effort it would take.
  3. I genuinely didn't know how a CMS actually delivers content to a site, things like font styling, YouTube embeds, code blocks, callouts. I could have figured all of it out eventually, but flying blind would have cost me a lot more time than it would have taught me.

So, I decided to use an existing headless CMS instead. The plan in my head was simple: make an account on one of these platforms, write content with a proper text editor, point it at my site with a webhook, hit publish, and I'd have a clean content pipeline set up in no time.
That's not quite how it went.

Picking Sanity and figuring out what "headless" actually means

I went back to Gemini, described what I wanted to do, and it told me Sanity was the most popular choice among developers and small startups. I didn't research too many alternatives, since I wasn't planning to write especially complex content, so I just went with it.

I made an account on Sanity, and to my surprise, the first thing it gave me wasn't a text editor, it was a snippet of code to run in my terminal to spin up something called a "studio." My first reaction was something like, what is this, I just wanted a text editor.

It turned out the text editor was coming, just not in the form I expected. What I was actually setting up was the "Sanity Studio," a portal that would be entirely my own. I followed the setup steps and got it running. Then it asked me to define a "schema," and that's when it clicked: I was building my own headless CMS after all, just with the boilerplate (the editor, the infrastructure) handled by Sanity, while I built the parts that actually mattered for learning.

It wasn't exactly what I'd pictured going in, but I was happy with it. I was learning more about how content management systems work than I expected to.

After talking it through with an LLM, I decided to restructure my project into a pnpm workspace monorepo, with a shared package for types and schemas that both the portfolio app and the Sanity Studio could use. The alternative would have been to host the studio inside the portfolio app itself, at something like `/admin`, but Sanity specifically recommends against that.

Before getting into how I actually configured and wired up Sanity in my portfolio, it's worth covering some general background on content management, since it helped me understand why headless CMS platforms exist in the first place.

A (very) brief history of content management

If you think about it, there are really only a handful of fundamentally different ways to manage content, with variations on each. At its core, content management comes down to two questions: how is content added, and how is it delivered?

  • Is content added directly in source code, stored in a database, or kept some other custom way?
  • Is it rendered on the fly (client-side or server-side), or pre-rendered and served as a static page?

There's no single "best" answer here. It depends on why you need content management in the first place: how complex the content is, how many people are writing it, whether there's a hierarchy of writers and editors, whether your writers even know HTML or Markdown, and on the performance side, how fast you need pages to load and how much dynamic behavior you actually need.

Roughly, the history looks like this:

  1. Early 90s — content was added directly in source code. A writer would write something, hand it to a developer, and the developer would hard-code it into the HTML.
  2. Late 90s — companies realized writers usually aren't developers, and that bottleneck needed solving. This is where monolithic "headful" CMS platforms like WordPress and Wix came from. Writers could finally write directly into the system, but everything from storage to rendering to serving was handled by one platform, usually with on-the-fly PHP rendering, and built specifically for the web.
  3. Mid-2000s — as mobile devices took off, content needed to reach more than just websites. This gave rise to decoupled CMS platforms, essentially the same WordPress-style systems but now exposing APIs to fetch content separately. It was a step forward, but still not a complete solution.
  4. Headless CMS — the idea became much simpler: the platform gives you a place to write, store, and manage content, and what you do with it (web, mobile, smartwatch, whatever framework or rendering strategy you want) is entirely up to you. This is the model that's taken over a large chunk of the market, and it's what I ended up using.

Today, you'll still find everything in active use, from raw source-code editing to advanced CMS platforms with full role-based access control for writers, senior editors, and publishers. What you should use really just depends on what you need.

Configuring the CMS and ISR

With the background out of the way, the last step was actually wiring all this into my project.

I went to Claude, explained the setup, and it generated a working implementation that matched what I needed. It defined schemas for "posts" and "tags," where each post had a title, slug, excerpt, cover image, related tags, and the content body itself, which included support for YouTube embeds, callout blocks, code blocks, and basic font styling. It also generated the corresponding TypeScript types, a few utility functions like readingTime, and I fed the schema into Sanity Studio.

From there, it built out the components to render the content on the page, set up a webhook, and created the /blog/[slug] page using static generation with Next.js ISR for revalidation.
By the end I had a mostly working setup, with two outstanding problems:

  1. The Presentation tool was broken. This is the feature that lets you preview exactly how a draft post will look once published, and it wasn't working.
  2. I didn't actually understand a lot of what had just been built. So I went back through it piece by piece, from how the schema was defined to how the content was rendered, to actually learn it.

I spent a day deep in Sanity's docs, going back and forth with both Claude and Gemini, and once I felt like I had a real handle on it, I rebuilt parts of the code myself, without LLM help, partly to fix the remaining bugs and partly just to test what I'd actually learned.
A few of the things I changed:

  • Removed the "tags" schema entirely, along with some parts of the "post" schema I didn't actually need.
  • Switched from hand-written types to Sanity's typegen. Claude had hard-coded the TypeScript types, which I later realized was a workaround, not a recommendation. Typegen produces more accurate types since they're generated directly from the schema, but it depends on a sanity.cli.ts file that normally lives in the Sanity Studio app. Since my shared sanity package was the single source of truth for types and schemas, I couldn't generate types from inside the studio app, so I had to restructure things to make typegen work from the shared package.
  • Fixed the Presentation tool bug in the studio.
  • Fixed a code-block rendering bug in the portfolio app, caused by a mismatch between how Shiki (the syntax highlighter) and Sanity's code input field name programming languages.

After a few hours of debugging, everything came together and started working the way it was supposed to.
Once it was all running, I figured this entire experience, the detours, the wrong turns, the things I learned along the way, was worth writing about. It seemed like a fitting topic for my first blog post.

If you want to see exactly how I set up the monorepo, schemas, and everything else, the full code is up on GitHub here, along with READMEs covering the important parts. The rest should make sense from reading the code itself.

Thanks for reading. If you're working through something similar, I'd say: let yourself take the detour. I learned a lot more from the wrong turns here than I would have from just shipping the obvious solution.

Thanks for reading. More posts on the blog.