DEV Community

Cover image for Next.js site with hardcoded content: add Sanity without a rebuild
Nayan Kyada
Nayan Kyada

Posted on Originally published at nayankyada.com

Next.js site with hardcoded content: add Sanity without a rebuild

Your Next.js site works, but every headline fix, price change, or new team member needs a developer and a deploy. That is the classic hardcoded content problem, and you do not need a rebuild to fix it. You can add Sanity CMS to the existing codebase page by page, keeping the design and URLs exactly as they are.

Why hardcoded content on a Next.js site gets expensive

The first symptom is small: someone wants to change a sentence and has to message a developer. The real cost shows up later.

  • Marketing waits days for changes that should take two minutes.
  • Developers become copy editors, and pull requests fill with typo fixes.
  • Content ends up scattered across JSX, constants files, and the odd JSON file, with no single place to see what the site says.
  • Nobody dares to touch pages because the copy is tangled with layout code.

If you recognise this, the site probably was not built wrong. It was built for launch, and content management was left for later. Later has arrived.

What you do not need to do

Owners often assume the answer is a full rebuild or a migration project. Usually it is not. If the frontend is on the App Router and reasonably clean, the components stay. Only the data flowing into them changes. If the site is still on the Pages Router or is an inherited codebase nobody understands, read what taking over an existing Next.js project involves first, because that changes the order of work.

Step 1: inventory what is actually editable

Not all hardcoded text should go into a CMS. I split it into three buckets:

  1. Editor content: headlines, body copy, testimonials, team members, FAQs, pricing, images. This goes into Sanity.
  2. Structural copy: button labels, form errors, navigation microcopy. Often fine to leave in code, or group into one small settings document.
  3. Logic and layout: stays in code.

Over-modelling is the most common mistake here. If you turn every string into a field, editors get a Studio with 200 inputs and stop using it. Start with the pages the marketing team changes most often. Usually that is the home page, a pricing page, and anything repeating like blog posts or case studies.

Step 2: model sections, not pages

A page that is a pile of hardcoded JSX usually has a handful of repeatable sections: hero, feature grid, testimonial strip, call to action. Model those as objects and let a page hold an array of them. That matches how your components already work.

// sanity/schemaTypes/hero.ts
import {defineField, defineType} from 'sanity'

export const hero = defineType({
  name: 'hero',
  title: 'Hero',
  type: 'object',
  fields: [
    defineField({name: 'heading', type: 'string', validation: (rule) => rule.required().max(90)}),
    defineField({name: 'subheading', type: 'text', rows: 3}),
    defineField({name: 'image', type: 'image', options: {hotspot: true}}),
    defineField({name: 'ctaLabel', type: 'string'}),
    defineField({name: 'ctaHref', type: 'string'}),
  ],
})
Enter fullscreen mode Exit fullscreen mode

Keep field names close to your existing component props. That makes the swap in step 4 almost mechanical. If you are unsure how to shape references and nesting, structuring Sanity schemas to avoid query waterfalls covers the decisions that are hard to undo later.

Step 3: import the current content, do not retype it

This is where migrations stall. Someone has to get the existing copy into Sanity, and retyping it by hand introduces mistakes. For a small site, I copy the text out of the components into a script that creates documents, then let editors review in the Studio. For larger content sets, the same approach used in a CMS move applies: write a script, run it against a non-production dataset first, and verify before it touches live content. The method is the same one I describe in the WordPress to Sanity technical walkthrough, just with a simpler source.

Use a separate dataset or at least a clear naming convention for test imports. Cleaning duplicates afterwards is tedious.

Step 4: swap one page at a time

The safe pattern is to leave the component untouched and change where its props come from. Here is the before and after for a home page in the App Router.

// app/page.tsx
import {notFound} from 'next/navigation'
import {client} from '@/sanity/lib/client'
import {Hero} from '@/components/Hero'

const HOME_QUERY = `*[_type == "page" && slug.current == "home"][0]{
  "hero": sections[_type == "hero"][0]{heading, subheading, ctaLabel, ctaHref}
}`

export default async function HomePage() {
  const page = await client.fetch(
    HOME_QUERY,
    {},
    {next: {revalidate: 3600, tags: ['page']}}
  )
  if (!page?.hero) notFound()

  // Before: <Hero heading="Hardcoded headline" ... />
  return <Hero {...page.hero} />
}
Enter fullscreen mode Exit fullscreen mode

The page still renders on the server, so search engines receive the same HTML as before. Copy the existing title and meta description into the schema too, and feed them through generateMetadata. Compare the rendered source before and after deploying. If anything differs that you did not intend, fix it before launch.

Step 5: make edits show up quickly

Editors expect to publish and see the change. Without revalidation, a CMS-backed page looks broken. Wire up a webhook that revalidates the tags you used above, and test it with a real publish before handing over. If editors later report that changes are not appearing, this troubleshooting guide for publishing that does not show on the live site walks through the usual causes.

What it costs to ignore

Every month on hardcoded content has a visible price: developer hours spent on copy changes, slow campaign launches, and a growing pile of content that becomes harder to extract the longer you wait. Adding Sanity early to a site with 5 pages is a few days of work. Adding it to a site with 80 pages and three years of inline edits is a project.

What to ask a developer before hiring them for this

  • Will the design, URLs, and rendered HTML stay the same? Ask them to show a before and after comparison.
  • How will existing content get into Sanity, by script or by retyping?
  • Which content will not be editable, and why? A good answer is a short list, not silence.
  • What do editors receive at the end: a trained walkthrough, field descriptions, and a working preview? The Sanity project handover checklist is a reasonable standard to hold anyone to.
  • Can the work be phased, with the highest-traffic page first?

Getting help with this

Adding Sanity to an existing Next.js site is work I do. If you want a clear picture of scope first, a performance and Sanity audit starts from $800, and full Sanity and Next.js builds start from $4,000. Details are on the services page.

Top comments (0)