Skip to main content
A Next.js site consumes @sp-stage/sdk and @sp-stage/admin exactly like an Astro site. The third package, @sp-stage/next, supplies the Next-shaped glue: the anchor helpers as React props, <StageAdmin> for the /admin route, renderers for pages and article bodies, the media slot, the preview canvas resolvers, and the on-demand publish handler. Everything on the other Developers pages applies; this section covers what differs.

The one design decision

The admin edits by writing directly into the canvas frame’s DOM: contenteditable text, grafted adds. Hydrated React would clobber those writes. So a Next site is split: The routers coexist natively. The canvas is an internal editor surface no visitor sees. A pure pages-router site works too; every pages-shaped helper remains exported.
next dev ignores unstable_runtimeJS, so dev canvases hydrate and can look fine while a production canvas is broken. Verify editing against a production build: next build && next start.

Zero JS means: anything a script was going to supply is missing

Two ways a canvas silently renders wrong. Check both on every route you add.
1

Data a client effect seeds

A component driven by a store that a useEffect fills renders nothing on the canvas. Pass the data in as props instead. PageRenderer and ArticleBody spread a context prop into every renderer for exactly this. The article canvas is the easy one to miss: wrap the article view in the site’s own shell and hand it the globals, or posts render with no footer while every page has one.
2

State a script was going to reveal

An image that fades in from opacity-0 in an onLoad handler stays transparent. A motion library’s initial={{ opacity: 0 }} is inlined as a style and never animates. Reveal them with canvas-scoped CSS (.stage-canvas img.opacity-0.transition-opacity { opacity: 1 }) rather than per component. Scope tightly: overlays meant to stay hidden until JS runs must stay hidden.

The three laws

  1. No time-based ISR on Stage pages. Stage’s semantic is live equals last publish. export const revalidate = N would regenerate in the background and leak saved-but-unpublished edits. Only the publish handler regenerates.
  2. The canvas is zero-JS. Components render complete without scripts. Anything a script reveals needs a canvas-scoped CSS rule or a props-passed data path.
  3. /admin loads zero site CSS. Site styles enter through the site layout group, the browse canvas and the pages _app, never the root layout. An unlayered Tailwind preflight beats the admin’s layered design system regardless of order, and every admin button flattens to transparent.

Requirements

  • Next 15 or later. Site routes in the App Router; the canvas as one pages-router file.
  • One React 19 everywhere. The admin shell is React 19; a React 18 host breaks it with an invalid hook call.
  • transpilePackages: ["@sp-stage/admin", "@sp-stage/sdk", "@sp-stage/next"] in the Next config.
  • Same origin for /admin, /preview/*, /browse/* and the site.
  • The admin shell’s two font files copied once from the package into public/fonts/.

The template

The Next client template is a minimal App Router site plus the pages-router canvas, a reference Hero, a site shell that takes globals as props, the blog, the browse canvas, the admin route with a reference schema, and the publish handler. Start a new Next site by cloning and renaming it. Its checklist:
  1. Rename the package and replace workspace dependencies with exact-pinned registry versions of the three packages.
  2. Delete the in-repo source aliases from the Next config and tsconfig.
  3. Create the org, fill the env.
  4. Seed pages and globals, or migrate from an existing CMS.
  5. Rebrand the tokens, build the components, register each type, grow the schema.
  6. Keep the blog base path identical in three places: the schema, the browse canvas, and the pages/preview/<base>/ directory (plus expandPaths in the publish handler).
  7. Run the canvas sweep on every route: footer present, nothing stuck at opacity 0.
  8. Deploy, then flip the org to revalidate publish mode with its secret.

Next steps

Wiring

Every file, with the code.

Edit anchors

The same attributes, as React props.