Frontend

Putting a Next.js site in front of it

Mount the API, mount the Studio, read content in a server component. The reference frontend in this repository is the worked example.

Three mounts and one read function is the whole integration.

The mounts

app/api/[...path]/route.tsts
export { GET, POST, PUT, PATCH, DELETE, OPTIONS } from '@neworange/content-next/api-route'
app/admin/[[...index]]/page.tsxtsx
export { default, metadata, viewport, dynamic } from '@neworange/content-next/studio-route'
app/images/[...path]/route.tsts
export { GET } from '@neworange/content-next/asset-route'

The app contains no business logic. Every route handler is a one-line re-export, which is the seam that keeps the platform replaceable and the app readable.

Reading content

app/_site/queries.tsts
import { contentQuery } from '@neworange/content-next/site'

export async function fetchPageBySlug(slug: string) {
  const { data } = await contentQuery<PageDocument | null>({
    query: `*[_type == "page" && slug.current == $slug][0]{ title, lead, sections }`,
    params: { slug },
  })
  return data
}

The queries live beside the pages that use them, in the app — not in a platform package. They are the one thing that is about the content model, and the content model belongs to whoever deploys this.

Rendering a page

app/[slug]/page.tsxtsx
export default async function Page({ params }) {
  const { slug } = await params
  const page = await fetchPageBySlug(slug)
  if (page === null) notFound()
  return <PageSections sections={page.sections ?? []} />
}

One thing to know about build-time rendering

A page cannot be prerendered at build time from its own deployment's API: during a build, the deployment is not serving yet. Either defer the route to request time, or use a dynamic segment with an empty generateStaticParams — which is not prerendered at build but is cached on first request, and is where incremental regeneration is actually observable.