Everything you need to run Broadsheet
Setup, schema generation, TypeGen, deployment, and customization — the full reference in one place. The same details found in the project's README, laid out for reading rather than skimming.
Quick start
Requires Node.js 20+ and a free Sanity project. Install once at the repo root — this is an npm workspaces monorepo, so a single install wires up both apps.
npm run setup logs you into Sanity in the browser, creates or links a cloud project, writes apps/studio/.env.local and apps/web/.env.local, creates API tokens, and optionally loads demo content for you.
Prefer manual setup? Copy .env.example → .env.local in both apps/web and apps/studio, and create a project yourself at sanity.io/manage.
Project structure
Two apps in one npm workspace:
| Folder | Description |
|---|---|
apps/web/ | Next.js 16 App Router site — articles, podcasts, columns, visual stories, RSS, search, Sanity TypeGen |
apps/studio/ | Sanity Studio with the editorial schema and homepage content desk |
Inside apps/web
Environment variables
The essentials — see apps/web/.env.example for the full list, including RSS limits, homepage layout counts, and social links.
| Variable | Purpose |
|---|---|
NEXT_PUBLIC_SANITY_PROJECT_ID | Your Sanity project ID |
NEXT_PUBLIC_SANITY_DATASET | Dataset name (usually production) |
NEXT_PUBLIC_SANITY_API_TOKEN | Read token — frontend fetches published content |
SANITY_API_WRITE_TOKEN | Write token — server-only, used by /api/revalidate |
SANITY_REVALIDATE_SECRET | Shared secret the Sanity webhook must send |
NEXT_PUBLIC_FRONTEND_URL | Canonical site URL — used in SEO, RSS, sitemap |
NEXT_PUBLIC_SITE_NAME | Publication name — shown as text masthead by default |
NEXT_PUBLIC_BRAND_COLOR | Primary accent color (defaults to the rust in this design) |
NEXT_PUBLIC_HEADER_BG | Header background color |
Sanity Studio
Document types available in the editorial schema:
| Type | _type | Purpose |
|---|---|---|
| Article | article | Long-form content, hero/main story flags, reviews |
| Author | author | Writers and podcast hosts |
| Category | category | News, opinions, reviews, etc. — slug drives frontend routes |
| Column | column | Columnist sections on the homepage |
| Podcast | podcast | Audio/video episodes |
| Topic | topic | Editorial topics |
| Trend | trend | Trending tags |
| Visual story | visualStory | Full-screen story format |
| Site settings | siteSettings | Singleton — About & Contact page copy |
Content setup checklist
siteSettingsnews, opinions, reviews) and mark nav items with Is Navigation itemNEXT_PUBLIC_DEFAULT_AUTHOR_SLUGcolumn documents and list their slugs in NEXT_PUBLIC_HOMEPAGE_COLUMNSSchema & TypeGen
GROQ queries in lib/queries.ts are typed end-to-end. TypeGen is a two-step pipeline: step 1 exports your Studio schema as JSON, step 2 reads that JSON plus your GROQ queries and writes TypeScript types.
| Step | Command | Runs from | Output |
|---|---|---|---|
| 1. Schema extract | sanity schema extract --path ../web/schema.json | apps/studio | apps/web/schema.json |
| 2. TypeGen generate | sanity typegen generate | apps/web | apps/web/sanity.types.ts |
Run both in one shot from the repo root:
Commands
| Command | What it does |
|---|---|
npm run typegen | Step 1 + step 2, one-shot |
npm run schema:extract | Step 1 only (alias: schema:sync) |
npm run typegen:generate | Step 2 only — needs schema.json to already exist |
npm run typegen:watch | Both watches running in parallel |
npm run dev:typegen | Step 2 watch only — pair with npm run dev:studio |
While actively developing schema
Run Studio dev and the TypeGen watcher side by side — Studio dev keeps schema.json in sync automatically (via schemaExtraction in sanity.cli.ts), and the watcher keeps sanity.types.ts in sync with it and with your GROQ queries:
apps/web/sanity.cli.ts is what points TypeGen at the right files:
After changing schema in apps/studio or editing a GROQ query in apps/web/lib, just run npm run typegen again if you're not already running the watchers.
Revalidation webhook
In Sanity, add a webhook that fires on publish and POSTs to your deployed site:
Configure it to send a secret header:
| Header | Value |
|---|---|
x-sanity-revalidate-secret | your SANITY_REVALIDATE_SECRET |
(Or send Authorization: Bearer <SANITY_REVALIDATE_SECRET> instead.) The route then:
Demo & seed data
Broadsheet ships fictional placeholder content, safe to redistribute. From the repo root, after setup:
Creates fictional authors, categories, ~22 articles, podcasts, and visual stories. Images come from picsum.photos placeholders; podcast audio uses a royalty-free demo MP3.
| Content | Count |
|---|---|
| Site settings | 1 |
| Authors | 4 |
| Categories | 3 |
| Topics | 6 |
| Trends | 3 |
| Columns | 2 |
| Articles | 22 |
| Podcasts | 4 |
| Visual stories | 2 |
Never export your real production dataset. Use npm run seed:bundle to build a clean, isolated demo dataset first — that's what gets packaged for distribution.
Customization checklist
.env.local — Sanity project + site name + URLNEXT_PUBLIC_SITE_NAME set — shows as a text masthead until logos are addedpublic/logo_light.png + logo_dark.png for automatic light/dark logos, no code changespublic/icon.png and apple-touch-icon.png before launchNEXT_PUBLIC_HOMEPAGE_COLUMNS to your column slugsNEXT_PUBLIC_GA_ID, or leave blank to skip analyticsDeploy
Netlify (recommended)
apps/webnpm run build.next (relative to the base directory — not apps/web/.next)apps/web/.env.exampleThe production build is pinned to webpack (next build --webpack in apps/web/package.json) rather than Next.js 16's new Turbopack-by-default build, to stay compatible with the current Netlify Next.js runtime. Safe to remove once that support matures.
Sanity Studio
Scripts reference
| Command | Description |
|---|---|
npm run dev | Web app dev server |
npm run dev:studio | Studio dev server |
npm run build | Production build (web) |
npm run setup | Sanity login, project, env files, optional seed |
npm run seed | Load fictional demo content |
npm run seed:bundle | Export a clean demo dataset for distribution |
npm run typegen | Schema extract + TypeGen generate |
npm run typegen:watch | Both TypeGen steps, watching |
npm run schema:extract | Schema extract only |
npm run deploy:studio | Deploy hosted Sanity Studio |
License
One purchase = one commercial project. Build it for yourself or for a single paying client per license — see the LICENSE file in your download for the full terms. Questions about licensing for multiple projects or agency use: hello@broadsheetkit.com.