Guide
Getting started
End-to-end setup for the ACTTA Studio Sanity Starter — from pulling the template into a new project through a live Vercel deploy with preview, webhooks, analytics, and form notifications.
Full docs (navigable): sanity-starter-guide.vercel.app
Prerequisites
- Node.js 20+ (nodejs.org)
- pnpm (
npm install -g pnpm) - A Sanity account and project
- A Vercel account for deployment
Optional later:
- Umami Cloud — analytics
- Resend — contact form email notifications
- Mux — video uploads in Studio
1. Get the starter
The starter lives in a template repository (this repo). You do not fork it for a new client project — you degit a clean copy into your own folder or repo.
Recommended: tiged (respects .degitignore)
tiged excludes folders listed in .degitignore — notably guide-site/, which is only for the deployed documentation app in the template repo.
npx tiged nonsoanetoh/sanity-starter --mode=git my-project
cd my-project
Template repo: github.com/nonsoanetoh/sanity-starter
What you get:
| Included | Excluded |
|---|---|
| Next.js app + embedded Studio | guide-site/ (separate Vercel project in the template repo) |
docs/ markdown for local reference | Template git history |
| Seed data, scripts, schemas | — |
Use the hosted guide for navigation and search: sanity-starter-guide.vercel.app. You do not need guide-site/ in your project.
Initialize your own git repo when ready:
git init
git add .
git commit -m "Initial commit from ACTTA Studio Sanity Starter"
Push to GitHub (or GitLab) before connecting Vercel in step 9.
Alternative: git clone
Use this if you are contributing to the template or working from a fork that should keep full history:
git clone https://github.com/nonsoanetoh/sanity-starter.git
cd sanity-starter
If you cloned the full template repo, you can delete guide-site/ locally — it is not required to run the starter.
Vanilla degit (no ignore support)
npx degit nonsoanetoh/sanity-starter my-project
cd my-project
rm -rf guide-site # not needed in your project
Prefer tiged so guide-site/ is never downloaded.
2. Install dependencies
pnpm install
Lefthook installs git hooks automatically via the prepare script.
3. Create your Sanity project
If you already have a project, skip to step 4.
- Go to sanity.io/manage
- Create a project (or use an existing one)
- Note your Project ID (e.g.
r94x15fe) - Use dataset
production(default)
4. Local environment
Run the setup wizard — it creates .env.local from .env.example if needed:
pnpm sanity:project-setup
Edit .env.local and fill in the required values:
NEXT_PUBLIC_URL=http://localhost:3000
NEXT_PUBLIC_SANITY_PROJECT_ID=your-project-id
NEXT_PUBLIC_SANITY_DATASET=production
NEXT_PUBLIC_SANITY_API_VERSION=2024-01-01
NEXT_PUBLIC_SANITY_STUDIO_BASE_PATH=/studio
| Variable | Required | Purpose |
|---|---|---|
NEXT_PUBLIC_SANITY_PROJECT_ID | Yes | Sanity project ID (browser + server) |
NEXT_PUBLIC_SANITY_DATASET | Yes | Usually production |
NEXT_PUBLIC_URL | Yes | Site URL for SEO and Presentation Tool |
NEXT_PUBLIC_SANITY_STUDIO_BASE_PATH | No | Defaults to /studio |
NEXT_PUBLIC_* vars are required for embedded Studio — the browser cannot read SANITY_STUDIO_*.
5. Sanity API tokens
Create tokens at sanity.io/manage → your project → API → Tokens.
Viewer token (draft preview)
- Add API token → name it
next-viewer - Role: Viewer
- Copy the token into
.env.local:
SANITY_API_VIEW_TOKEN=your-viewer-token
Enables draft mode, live preview in Presentation, and SanityLive subscriptions locally.
Editor token (contact forms)
- Add API token → name it
next-editor - Role: Editor
- Copy into
.env.local:
SANITY_API_EDIT_TOKEN=your-editor-token
Required for contact form submissions to write contactFormSubmission documents in Sanity.
6. CORS origins (local)
In Sanity → API → CORS origins, add:
| Origin | Allow credentials |
|---|---|
http://localhost:3000 | Yes |
Credentials are required for live preview and draft mode.
7. Import seed content
Load the starter homepage, site settings, and sample content:
pnpm sanity:project-setup --import-seed
# or
pnpm sanity:dataset-import
Visit:
- Site: http://localhost:3000
- Studio: http://localhost:3000/studio
8. Verify locally
- Homepage loads at
/ - Studio loads at
/studio— sign in with your Sanity account - Edit a page section → open Presentation → confirm live preview updates without a full refresh — see features/draft-mode.md
- Submit the contact form (requires
SANITY_API_EDIT_TOKEN) — see features/contact-forms.md
9. Deploy to Vercel
Connect the repo
- Import the project at vercel.com/new
- Settings:
| Setting | Value |
|---|---|
| Framework | Next.js |
| Build command | pnpm build |
| Install command | pnpm install |
Environment variables
Copy all values from .env.local into Vercel → Settings → Environment Variables.
Required for production:
| Variable | Example |
|---|---|
NEXT_PUBLIC_SANITY_PROJECT_ID | your project ID |
NEXT_PUBLIC_SANITY_DATASET | production |
NEXT_PUBLIC_URL | https://your-app.vercel.app |
SANITY_API_VIEW_TOKEN | Viewer token |
SANITY_API_EDIT_TOKEN | Editor token |
SANITY_REVALIDATE_SECRET | random secret (see step 10) |
Use the base Vercel URL for NEXT_PUBLIC_URL — no trailing slash, no /studio.
Deploy once to get your live URL, then update NEXT_PUBLIC_URL if needed and redeploy.
10. Revalidation webhook
The webhook clears Next.js cache when content is published so the live site updates within seconds.
Deploy-first order
Do these in order — creating the webhook before the site is live will cause failed test deliveries:
- Deploy to Vercel and confirm the site loads
- Set
NEXT_PUBLIC_URLto your base Vercel URL and redeploy - Generate and add
SANITY_REVALIDATE_SECRETto Vercel, then redeploy again - Create the webhook in Sanity pointing at your live
/api/revalidateURL
Draft and preview changes do not use the webhook — only published content triggers revalidation.
Generate a secret
openssl rand -base64 32
Add to Vercel and .env.local:
SANITY_REVALIDATE_SECRET=your-generated-secret
Redeploy after adding the env var — the running app must have the secret at build/runtime.
Create the webhook in Sanity
sanity.io/manage → your project → API → Webhooks → Create webhook
| Field | Value |
|---|---|
| URL | https://your-app.vercel.app/api/revalidate |
| Dataset | production |
| Trigger on | Create, Update, Delete |
| Projection | { _id, _type, "uri": uri.current, "slug": slug.current } |
| Secret | same value as SANITY_REVALIDATE_SECRET |
Test the webhook from Sanity — expect { "revalidated": true, "tags": [...] }.
Then publish a visible change in Studio and confirm the production site updates within a few seconds.
Troubleshooting
| Response | Cause | Fix |
|---|---|---|
501 Revalidation not configured | SANITY_REVALIDATE_SECRET not set on Vercel, or no redeploy since adding it | Add env var and redeploy |
401 Invalid signature | Secret mismatch between Vercel and Sanity webhook | Copy the exact same secret to both places |
| Connection / timeout error | Wrong URL, site not deployed, or typo in domain | Verify URL loads; use base domain + /api/revalidate |
Site-wide Basic Auth does not block /api/revalidate — webhooks work even when the public site is gated.
See also deployment/vercel.md and faq.md.
11. CORS origins (production)
Add your deploy URL in Sanity → API → CORS origins:
| Origin | Allow credentials |
|---|---|
https://your-app.vercel.app | Yes |
Use the base URL only — not /studio.
12. Umami analytics (optional)
Privacy-friendly page analytics. The script only loads when configured.
- Sign up at cloud.umami.is
- Settings → Websites → Add website
- Domain:
your-app.vercel.app(nohttps://, no trailing slash) - Copy the Website ID
Add to Vercel (and .env.local for local testing):
NEXT_PUBLIC_UMAMI_WEBSITE_ID=your-website-id
NEXT_PUBLIC_UMAMI_HOST=https://cloud.umami.is
Redeploy — NEXT_PUBLIC_* vars are baked in at build time.
Verify: DevTools → Network → cloud.umami.is/script.js loads on your site.
See features/umami-tracking.md.
13. Resend email notifications (optional)
Contact forms always save to Sanity when SANITY_API_EDIT_TOKEN is set. Email notifications are optional.
Resend setup
- Create an account at resend.com
- Add and verify a sending domain (or use Resend's test domain for development)
- Create an API key
Add to Vercel and .env.local:
RESEND_API_KEY=re_xxxxxxxx
RESEND_EMAIL_FROM=notifications@yourdomain.com
Studio configuration
In Studio → Site → Forms, add one or more Form notification emails.
When both Resend env vars are set and recipients are configured, successful form submissions trigger an email in addition to the Sanity document.
See features/contact-forms.md.
14. Staging gate with Basic Auth (optional)
For pre-launch review on Vercel:
BASIC_AUTH_USERNAME=your-user
BASIC_AUTH_PASSWORD=your-password
Then in Studio → Site → Security, enable Enable site-wide Basic Auth.
Env vars alone do not gate the site — the CMS toggle must be on. Studio (/studio) and /api/* routes stay accessible without auth.
15. Mux video (optional)
For video uploads in Studio:
- Create a Mux account and generate API access tokens
- Add to
.env.local(Studio only — not needed on the frontend):
SANITY_STUDIO_MUX_TOKEN_ID=your-mux-token-id
SANITY_STUDIO_MUX_TOKEN_SECRET=your-mux-token-secret
Final checklist
GET THE STARTER
☐ tiged into new folder (or git clone if contributing to template)
☐ git init + push to your remote (before Vercel)
☐ pnpm install
LOCAL
☐ pnpm install
☐ .env.local filled in (project ID, dataset, URL)
☐ Viewer token → SANITY_API_VIEW_TOKEN
☐ Editor token → SANITY_API_EDIT_TOKEN
☐ CORS: http://localhost:3000 (credentials enabled)
☐ Seed imported
☐ pnpm dev — site and Studio work
☐ Presentation live preview works
VERCEL
☐ Repo connected, deploy succeeds
☐ All env vars copied to Vercel
☐ NEXT_PUBLIC_URL = base Vercel URL
☐ Redeployed after env changes
SANITY (PRODUCTION)
☐ CORS: production URL (credentials enabled)
☐ Webhook → /api/revalidate with matching secret
☐ Publish test → live site updates
OPTIONAL
☐ Umami website ID in NEXT_PUBLIC_UMAMI_WEBSITE_ID
☐ Resend API key + from address + notification emails in Site
☐ Basic Auth env vars + toggle in Site → Security
☐ Mux tokens for video uploads
Next steps
- Commands reference — all
pnpmscripts and code generation - Draft mode & preview
- Content architecture
- Agent guide — read before making changes