BACK TO BLOG

Next.js App Router Blog with Sanity (SSR): A Beginner-Friendly Build + Caching Explained

nextjsapp-routersanityssrcachingseovercel

If you’re building a personal site on Vercel and want to add a blog, Next.js App Router + Sanity is a sweet spot: you get server-first rendering (less client JS), a real editor experience in Sanity Studio, and solid SEO via Next’s Metadata API.

But the part that confuses most people isn’t the routes—it’s caching. “Why didn’t my new post show up?” is almost always a caching-layer question. We’ll build the blog and then make updates instant with a webhook + `revalidatePath()`.

What we’re building

A simple blog with two routes:

  • `/blog`: index page that lists posts
  • `/blog/[slug]`: individual post page

Sanity will store the content (title, slug, excerpt, tags, Portable Text body), and Next.js will fetch and render it on demand (SSR) on Vercel.

App Router mental model (quick and useful)

With App Router, your `page.tsx` is a Server Component by default. That means you can fetch on the server directly (no client hooks needed) and ship less JavaScript to the browser.

If you want fully dynamic server rendering (no build-time data requirements), you can configure a route segment as dynamic. That’s perfect for blogs backed by a CMS.

Sanity content model (minimal schema)

Start with a single `post` type:

  • title (string), slug (slug), publishedAt (datetime)
  • excerpt (text), tags (array of strings)
  • content (Portable Text blocks)

Fetching posts with GROQ (what you actually need)

You typically need two queries: a list query for the index and a single-post query by slug. Also, it’s common to filter out future posts by checking `publishedAt <= now()`.

Render Portable Text (clean defaults)

Portable Text is Sanity’s rich text format. In Next.js, the simplest reliable approach is `@portabletext/react` with a small set of components for headings, paragraphs, lists, and links.

SEO the easy way: `generateMetadata()` per post

For the index page, a static `metadata` export is enough. For post pages, `generateMetadata()` lets you fetch the post and set title/description/OpenGraph dynamically (so shares look good and search results are accurate).

Caching explained (the part that saves you hours)

When you use Sanity + Next.js, there are two independent caches you must reason about:

  • Layer 1: the Sanity CDN (`useCdn: true` caches responses at the edge for speed)
  • Layer 2: the Next.js Data Cache (server fetch caching controlled by `revalidate` or `tags`)

If your content looks stale, it can be because of either cache—or both. Once you accept that, debugging becomes straightforward.

Strategy options

There are three common strategies:

  • Time-based revalidation: refresh every N seconds (simple)
  • Path-based revalidation: refresh a specific URL when a post changes (great for blogs)
  • Tag-based revalidation: refresh all cached queries tagged `post`/`author`/etc (great at scale)

Make updates instant: Sanity webhook → Next route → `revalidatePath()`

The nicest workflow is: you publish a post in Sanity Studio, and your Next.js site updates immediately—without waiting for a revalidate timer.

At a high level:

  1. Create a Next.js route handler (e.g. `/api/revalidate/path`) secured by a secret.
  2. Create a Sanity webhook that POSTs `{ path: "/blog/<slug>" }` when a post is created/updated/published.
  3. In the handler, validate the signature/secret and call `revalidatePath(body.path)`.

This gives you the best of both worlds: aggressive caching for performance and instant updates when content changes.

Deployment checklist (Vercel)

  • Set `NEXT_PUBLIC_SANITY_PROJECT_ID`, `NEXT_PUBLIC_SANITY_DATASET`, `NEXT_PUBLIC_SANITY_API_VERSION` in Vercel env vars.
  • If using webhook revalidation, set `SANITY_REVALIDATE_SECRET` and configure the webhook to use it.
  • Test on a preview deployment: publish a post → confirm `/blog` and `/blog/[slug]` update.

Closing thoughts

A blog is a perfect App Router project because it forces you to learn the most important Next.js skills: server-first rendering, metadata, and caching. Once you understand the two caching layers, everything else becomes much easier—and your CMS workflow becomes genuinely pleasant.