# The Content Architecture (Next.js)A modern Next.js 16.3 starter with Sanity CMS integration: content model, in-app Studio, and product features, running on a Next.js App Router frontend.## Features- Next.js 16.3 with the App Router and Server Components: the Studio and the API routes live on the same origin as the site- Sanity CMS with the Studio mounted at `/studio`- The pages model: a catch-all route renders any `page` document by its `uri`, homepage included- Reusable page builder (text, media, headline, CTA, contact form sections) rendered by self-fetching Server Components- Rich text via Portable Text with media blocks, inline media, links, colors- Media pipeline: Sanity images (responsive srcset + LQIP), Mux video, native video, Lottie, and Rive- Draft mode with the Presentation tool, Sanity Live, and Visual Editing overlays- SEO helpers: per-page metadata with Site singleton fallbacks, og:image cropping, per-scheme favicons plus a stable `/favicon.ico` for Google, JSON-LD, CMS-driven sitemap and robots- **Cache Components** ([the modern Next.js caching model](https://nextjs.org/docs/app/getting-started/cache-components)): every page prerenders into a static shell with a one-year lifetime, and publishing in the Studio is the only revalidation signal (webhook + tags, no timers). See [`docs/sanity/revalidation-and-caching.md`](docs/sanity/revalidation-and-caching.md).- **HTTP Basic Auth (optional)**: `proxy.ts` gates the site or individual URLs using `BASIC_AUTH_*` environment variables and CMS toggles (Site, Security; per-entry "Password protect"). See [`docs/features/basic-auth.md`](docs/features/basic-auth.md).- **RSS feed**: [`/feed.xml`](docs/features/rss-feed.md) serves the blog as RSS 2.0 with full article bodies, autodiscovered from the blog pages.- **llms.txt for AI assistants**: an editable, AI-generated [`/llms.txt`](https://llmstxt.org) drafted from your content with Sanity Agent Actions (Site, Agents tab). See [`docs/features/llms-txt.md`](docs/features/llms-txt.md).- **Agent Markdown (content negotiation)**: pages and articles serve a token-light Markdown version to agents that send `Accept: text/markdown`, on the same URL. Generated and stored per page from the Agents tab (one click), then served verbatim. See [`docs/features/agent-markdown.md`](docs/features/agent-markdown.md).- **Real 404s**: an unknown path answers a genuine `404`, decided in `proxy.ts` before the response starts, rather than the `200` a streamed shell would return. Agents get a short Markdown recovery map instead of an error string, so one that followed a stale link can re-orient. See [`docs/features/agent-404.md`](docs/features/agent-404.md).- **Published API description**: [`/openapi.json`](https://spec.openapis.org/oas/v3.1.0) describes the public endpoints for agents, titled from your Site singleton, alongside one JSON error shape (`error`, `code`, `hint`) across the API routes. See [`docs/features/openapi.md`](docs/features/openapi.md).- CMS-managed redirects baked into the build from the Settings singleton- Feature modules for Umami analytics and spam prevention- Scaffolding via Plop for repeatable section/route/block generation- **A superset you can trim**: `npm run trim` removes a feature you do not need (blog, legal pages, contact form, the form layer, the announcement bar, Umami, the OpenAPI description, a media kind, a page-builder section) across its files, registries, docs, dependencies and Sanity content, or refuses to start. See [`docs/features/trimming-features.md`](docs/features/trimming-features.md).- Starter **seed dataset** (`seed/`), imported by `npm run sanity:project-setup` so a new project boots with example content- Contact form with honeypot + timing spam prevention and Resend notifications- [`@mantine/hooks`](https://mantine.dev/hooks/getting-started/) for shared React hooks; `features/dom/use-breakpoint.ts` wraps [`useMediaQuery`](https://mantine.dev/hooks/use-media-query/) for Tailwind-aligned breakpoints and touch detection, alongside `constants` / `parseResponsiveValues`## Getting Started**New here? Start with [`GETTING-STARTED.md`](GETTING-STARTED.md).** It is the guided, top to bottom path from a fresh clone to your first rendered section. The sections below are the reference.### Prerequisites- Node.js 24.15.0, pinned in `.nvmrc` and in `package.json` (`engines`, `volta`). `engines` requires the `^24.15.0` LTS line, so npm refuses to install on any other major.- npm >= 11.6.2### Installation```bashnpm install```### Environment VariablesCopy `.env.example` to `.env` and fill it in. The minimum for local dev:```envNEXT_PUBLIC_URL=http://localhost:3000NEXT_PUBLIC_SANITY_PROJECT_ID=your-project-idNEXT_PUBLIC_SANITY_DATASET=productionNEXT_PUBLIC_SANITY_API_VERSION=2025-02-19NEXT_PUBLIC_SANITY_STUDIO_BASE_PATH=/studioSANITY_API_VIEW_TOKEN=your-view-tokenSANITY_API_EDIT_TOKEN=your-edit-token````npm run sanity:project-setup` creates the project, both tokens, CORS entries, and writes `.env` for you.`NEXT_PUBLIC_SANITY_STUDIO_BASE_PATH` is the **public** URL for Studio. The app mounts Studio under `app/sanity-studio/…`; `next.config.ts` rewrites the public path to that folder. If a **content page** must use the same path (e.g. you need `/studio` for a page), set this variable to a different path (e.g. `/admin`) in every environment. See [`docs/sanity/studio-and-structure.md`](docs/sanity/studio-and-structure.md#public-url-rewrites-and-reserved-paths).### HTTP Basic Auth (optional)For staging or client-review gates, set `BASIC_AUTH_USERNAME` and `BASIC_AUTH_PASSWORD` in the same environment as the app. Turn protection on in Sanity (site-wide and/or per document with "Password protect"); credentials are not stored in the CMS. Full behavior: [`docs/features/basic-auth.md`](docs/features/basic-auth.md).### Seed starter content`npm run sanity:project-setup` imports the bundled example content at the end of its run, unless you answer its last question with **Completely empty**. To load it separately (a blank dataset, a second dataset, a reset), with the CLI authenticated (`npm run sanity:cli -- login`):```bashnpm run sanity:dataset-import -- --file seed/seed-dataset.tar.gz```See [`docs/sanity/seed-dataset.md`](docs/sanity/seed-dataset.md).### Development```bashnpm run dev```- Site: [http://localhost:3000](http://localhost:3000)- Studio: `http://localhost:3000` + your `NEXT_PUBLIC_SANITY_STUDIO_BASE_PATH` (default `/studio`)### Build```bashnpm run buildnpm run start````next build` prerenders every page into a static shell with a one-year lifetime, so a deploy is not what refreshes content: publishing in the Studio is. That takes a Sanity webhook pointed at `/api/revalidate`, created once by hand and secured with `SANITY_REVALIDATE_SECRET`. See [`docs/sanity/revalidation-and-caching.md`](docs/sanity/revalidation-and-caching.md).## DocsFeature-level docs live in `docs/` so the root README stays lightweight. Start at [`docs/README.md`](docs/README.md).## Scripts- `npm run dev`: Start the dev server (site + Studio + APIs)- `npm run build`: Build for production (`next build`)- `npm run start`: Start the production server- `npm run check`: Run all checks (`check.*` in parallel)- `npm run check.types`: TypeScript type checking- `npm run check.biome`: Biome lint (errors only)- `npm run format`: Format and fix with Biome (`biome check --write --unsafe`)- `npm test`: Run the unit tests- `npm run plop`: Scaffold new sections, prefix routes, and rich text blocks- `npm run trim`: Interactively remove a feature you do not need (code, docs, dependencies, and optionally its Sanity content)- `npm run trim -- --status`: What this project has of the starter: each feature's state, its content per dataset, and the code that imports it- `npm run trim -- --dataset-only --dry-run`: Report Sanity content whose type the schema no longer declares; drop `--dry-run` to delete it- `npm run trim:update`: Take the starter's current trim into this project, keeping `scripts/trim-features/project.json`- `npm run clear`: Remove local build and cache output (`.next`, `node_modules/.cache`)- `npm run sanity:typegen`: Extract the Sanity schema and generate `sanity/types.ts`- `npm run sanity:cli`: Run the Sanity CLI with `.env` loaded (via dotenvx)- `npm run sanity:schema-deploy`: Deploy the schema to Sanity (required by Agent Actions)- `npm run sanity:dataset-export`: Backup a dataset to `./backups/`- `npm run sanity:dataset-import`: Restore a `.tar.gz` into a dataset- `npm run sanity:dataset-migrate`: Copy one dataset into anotherEvery `sanity:*` script above is interactive: run it with no flags and it asks what it needs, prints a summary, and confirms before touching anything. Flags answer those questions up front, `--dry-run` prints the plan and stops, and `--yes` skips every prompt (see `scripts/README.md`).- `npm run sanity:project-setup`: Interactive wizard for a Sanity project, tokens, CORS, and `.env`## Project Structure```text.|-- app/| |-- (web)/ # Site routes ([[...uri]] is the pages model) and the page shell| |-- api/ # Route handlers (served at /api/*)| `-- sanity-studio/ # Studio mount, rewritten to your public Studio path|-- components/ # Shared React components (Button, Icon, Dialog)|-- features/ # Feature modules (page-builder, site, agents, sanity, rich-text, style, ...)|-- public/ # Static assets|-- sanity/ # Sanity Studio config, schema, structure (standalone folder)|-- seed/ # Starter dataset shipped with the template|-- scripts/ # Dataset + project-setup CLIs|-- templates/ # Plop templates|-- docs/ # Project documentation|-- proxy.ts # Basic Auth + agent Markdown negotiation + real 404s|-- env.ts # Typed environment config`-- next.config.ts # Cache Components, Studio rewrite, CMS redirects```## Agent SkillsAI guidance for this repository lives in `AGENTS.md` and `.agents/skills/`.## Learn More- [Next.js Documentation](https://nextjs.org/docs)- [Sanity Documentation](https://www.sanity.io/docs)- [Tailwind CSS Documentation](https://tailwindcss.com/docs)## LicenseCommercial, one license per buyer. Build unlimited personal, commercial, and client projects with it, and sell what you build. Do not resell or republish the boilerplate itself.See [`LICENSE.md`](LICENSE.md) for the full terms, and the [Terms of Service](https://www.contentarchitecture.dev/terms-of-service) for the purchase terms.