How AI is powering better personalization in e-commerce [with Vercel]. Sign up now →

SanTan

Tanstack Start with Sanity Visual Editing

By Magne Hustveit


README

Santan Monorepo

A production-ready monorepo combining a React frontend with Sanity Studio, powered by Turborepo.


šŸ“‹ Table of Contents


Overview

This monorepo combines a React frontend and Sanity Studio into a single, optimized workspace with:

āœ… Shared type system - Auto-generated Sanity types used across both apps
āœ… Turborepo caching - Lightning-fast builds with intelligent caching
āœ… Production-ready - Properly configured for deployment
āœ… Type-safe - Full TypeScript support throughout
āœ… Hot reloading - Fast development experience

Tech Stack

Frontend (apps/frontend)

  • React 19
  • TanStack Router & Query
  • Vite 7
  • Sanity Client
  • Tailwind CSS

Studio (apps/studio)

  • Sanity Studio 4
  • Custom schema types
  • Document preview

Shared (packages/shared)

  • Auto-generated Sanity types
  • Shared utilities
  • Type-safe enums

Quick Start

Prerequisites

  • Node.js ≄ 18
  • npm (comes with Node.js)
  • Sanity account with a configured project

1. Clone and Install

cd /path/to/santan-monorepo
npm install

2. Configure Environment

Frontend:

cp apps/frontend/.env.example apps/frontend/.env.local

Edit apps/frontend/.env.local:

VITE_SANITY_PROJECT_ID=your_project_id
VITE_SANITY_DATASET=production
VITE_SANITY_API_VERSION=2024-01-01
SESSION_SECRET=generate_a_random_secret_here

Studio:

cp apps/studio/.env.example apps/studio/.env.local

Edit apps/studio/.env.local:

SANITY_STUDIO_PROJECT_ID=your_project_id
SANITY_STUDIO_DATASET=production

3. Start Development

npm run dev

This starts:


Project Structure

santan-monorepo/
ā”œā”€ā”€ apps/
│   ā”œā”€ā”€ frontend/              # React frontend
│   │   ā”œā”€ā”€ src/
│   │   │   ā”œā”€ā”€ routes/       # TanStack Router routes
│   │   │   ā”œā”€ā”€ components/   # React components
│   │   │   ā”œā”€ā”€ sanity/       # Sanity queries and loaders
│   │   │   └── types/        # Frontend-specific types
│   │   ā”œā”€ā”€ .env.local        # Environment variables (not in git)
│   │   └── package.json      # @santan/frontend
│   │
│   └── studio/                # Sanity Studio
│       ā”œā”€ā”€ src/
│       │   ā”œā”€ā”€ schemaTypes/  # Content schemas
│       │   ā”œā”€ā”€ structure/    # Studio structure
│       │   └── scripts/      # Type generation scripts
│       ā”œā”€ā”€ .env.local        # Environment variables (not in git)
│       └── package.json      # @santan/studio
│
ā”œā”€ā”€ packages/
│   └── shared/                # Shared package (auto-generated types)
│       ā”œā”€ā”€ src/
│       │   ā”œā”€ā”€ types/
│       │   │   ā”œā”€ā”€ sanity.types.ts       # Generated Sanity types
│       │   │   └── sanityTypeLiterals.ts # Type literal enums
│       │   └── index.ts      # Main export
│       ā”œā”€ā”€ dist/             # Compiled output (generated)
│       └── package.json      # @santan/shared
│
ā”œā”€ā”€ turbo.json                 # Turborepo configuration
ā”œā”€ā”€ package.json               # Root package with workspaces
ā”œā”€ā”€ README.md                  # This file
└── docs/
    ā”œā”€ā”€ TYPE_MIGRATION.md      # Type generation guide
    └── PRODUCTION_READY.md    # Production deployment guide

Development

Run All Apps

npm run dev

Starts all workspaces with hot reloading:

  • Frontend dev server
  • Studio dev server
  • Shared package in watch mode (auto-rebuilds on changes)

Run Individual Apps

# Frontend only
npm run dev --workspace=@santan/frontend

# Studio only
npm run dev --workspace=@santan/studio

# Shared package only (watch mode)
npm run dev --workspace=@santan/shared

Working with Shared Types

The @santan/shared package contains auto-generated Sanity types:

// Import in Frontend or Studio
import { 
  Post, 
  Category, 
  Author,
  sanityTypeLiterals 
} from '@santan/shared/types';

// Type-safe document checking
if (doc._type === sanityTypeLiterals.post) {
  // TypeScript knows doc is Post type
  console.log(doc.title, doc.slug);
}

Production

Building for Production

npm run build

This builds all packages in the correct order:

  1. Shared package → Compiles TypeScript to JavaScript
  2. Studio → Builds Sanity Studio (using shared types)
  3. Frontend → Builds React app (using shared types)

Build Output

  • Frontend: apps/frontend/.output/ (Nitro/Vite output)
  • Studio: apps/studio/dist/ (Sanity Studio build)
  • Shared: packages/shared/dist/ (Compiled types)

Deployment

Frontend (Vercel/Netlify):

  • Root directory: apps/frontend
  • Build command: npm run build
  • Output directory: apps/frontend/.output or apps/frontend/dist

Studio (Sanity):

cd apps/studio
npm run deploy

Or from root:

npm run deploy --workspace=@santan/studio

See packages/shared/PRODUCTION_READY.md for complete deployment guide.


Type Generation

When to Regenerate Types

Run type generation whenever you:

  • Add a new document type in Sanity Studio
  • Modify existing schemas
  • Change field definitions
  • Update portable text configurations

Generate Types

cd apps/studio
npm run generate-types

What this does:

  1. Extracts Sanity schema → schema.json
  2. Generates TypeScript types → packages/shared/src/types/sanity.types.ts
  3. Extracts type literals → packages/shared/src/types/sanityTypeLiterals.ts

The shared package automatically rebuilds (if dev mode is running), making types instantly available to both Frontend and Studio.

See TYPE_MIGRATION.md for detailed type generation workflow.


Available Commands

Root Commands

CommandDescription
npm run devStart all apps in development mode
npm run buildBuild all apps for production
npm run type-checkType check all packages
npm run lintLint all packages
npm run formatFormat code with Prettier
npm run cleanClean build artifacts

Workspace Commands

Run commands in specific packages:

# Pattern
npm run <command> --workspace=@santan/<package>

# Examples
npm run dev --workspace=@santan/frontend
npm run build --workspace=@santan/studio
npm run type-check --workspace=@santan/shared

Documentation


Troubleshooting

Port Already in Use

If ports 3000 or 3333 are in use:

# Kill processes on specific ports
lsof -ti:3000 | xargs kill -9
lsof -ti:3333 | xargs kill -9

# Or kill all dev servers
pkill -f "npm run dev"

Frontend Can't Connect to Sanity

Check your .env.local files:

  • āœ… VITE_SANITY_PROJECT_ID matches your Sanity project
  • āœ… VITE_SANITY_DATASET is correct (usually "production")
  • āœ… VITE_SANITY_API_VERSION is valid

Types Not Updating

  1. Regenerate types:

    cd apps/studio
    npm run generate-types
  2. If dev mode is running, shared package should auto-rebuild

  3. Otherwise, manually build:

    cd packages/shared
    npm run build
  4. Restart TypeScript server in your IDE:

    • VS Code: CMD+Shift+P → "TypeScript: Restart TS Server"
    • WebStorm: Should auto-reload

"Cannot find module" Errors

Ensure dependencies are installed:

npm install

If issues persist, clean and reinstall:

npm run clean
rm -rf node_modules apps/*/node_modules packages/*/node_modules
npm install

Build Errors in Production

Ensure the shared package is built before other packages:

cd packages/shared && npm run build
cd ../..
npm run build

Turborepo should handle this automatically with the ^build dependency.


Benefits of This Monorepo

For Development

āœ… Single clone - Get frontend and studio together
āœ… Shared types - Auto-generated, always in sync
āœ… Fast builds - Turborepo caches everything
āœ… Hot reloading - Changes reflect immediately
āœ… Type safety - Full TypeScript support

For Production

āœ… Optimized builds - Only rebuild what changed
āœ… Type-safe deployments - Compile-time type checking
āœ… Atomic commits - Change frontend and studio together
āœ… Single source of truth - One repo, one package.json

For Teams

āœ… Easier onboarding - Clone once, everything works
āœ… Consistent tooling - Same linting, formatting, testing
āœ… Simplified CI/CD - One pipeline for everything
āœ… Better collaboration - See all changes in one place


Support & Resources

Powering ShareScan.io: https://sharescan.io


License

MIT


Status: āœ… Production Ready
Last Updated: October 30, 2025