Skip to main content
Sanity Studio is an open-source, single-page application (SPA) for content management. It’s built with React and TypeScript, designed to be highly customizable through a plugin architecture.

Overview

Key characteristics:
  • React-based SPA - Modern component architecture
  • Real-time collaboration - Multiple users can edit simultaneously
  • Schema-driven - Content structure defined in JavaScript/TypeScript
  • Highly extensible - Plugin system for customization
  • GROQ-powered - Graph-Oriented Query Language for data access

Repository structure

Sanity Studio is developed as a monorepo containing multiple packages:
sanity/
β”œβ”€β”€ packages/                    # All publishable and internal packages
β”‚   β”œβ”€β”€ sanity/                 # Main studio package (the "sanity" npm package)
β”‚   β”œβ”€β”€ groq/                   # GROQ language utilities
β”‚   β”œβ”€β”€ @sanity/                # Scoped public packages
β”‚   β”‚   β”œβ”€β”€ cli/               # Command-line interface
β”‚   β”‚   β”œβ”€β”€ types/             # TypeScript type definitions
β”‚   β”‚   β”œβ”€β”€ schema/            # Schema compilation and validation
β”‚   β”‚   β”œβ”€β”€ mutator/           # Document mutation logic
β”‚   β”‚   β”œβ”€β”€ diff/              # Document diffing utilities
β”‚   β”‚   β”œβ”€β”€ vision/            # GROQ query tool (Studio plugin)
β”‚   β”‚   └── ...
β”‚   └── @repo/                  # Internal monorepo tooling
β”œβ”€β”€ dev/                        # Development studios for testing
└── examples/                   # Example projects

Package dependency graph

The packages have a layered dependency structure:
                                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                                    β”‚     sanity      β”‚  (main studio package)
                                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                             β”‚
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
              β”‚                              β”‚                              β”‚
              β–Ό                              β–Ό                              β–Ό
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”           β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”           β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚   @sanity/cli   β”‚           β”‚  @sanity/schema β”‚           β”‚ @sanity/vision  β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜           β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜           β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
             β”‚                             β”‚
             β–Ό                             β–Ό
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”           β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚ @sanity/codegen β”‚           β”‚ @sanity/mutator β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜           β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                           β”‚
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚                      β”‚                      β”‚
                    β–Ό                      β–Ό                      β–Ό
          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
          β”‚  @sanity/types  β”‚    β”‚   @sanity/diff  β”‚    β”‚   @sanity/util  β”‚
          β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Key packages

PackageDescription
sanityMain studio package containing UI, form builder, structure tool, and core functionality
@sanity/cliCommand-line interface for project management, builds, and deployments
@sanity/typesTypeScript type definitions for documents, schemas, and common data structures
@sanity/schemaSchema compilation, validation, and type inference
@sanity/mutatorDocument mutation logic for real-time collaboration
@sanity/diffGenerates diffs between documents for change tracking
@sanity/visionGROQ query playground tool (Studio plugin)

Studio and workspace architecture

The Studio is configured using defineConfig() which creates one or more workspaces. Each workspace represents an independent content environment with its own:
  • Project ID and Dataset - Connection to Content Lake
  • Schema - Document and field type definitions
  • Plugins - Extended functionality
  • Tools - Top-level navigation views
import {defineConfig} from 'sanity'
import {structureTool} from 'sanity/structure'

export default defineConfig({
  name: 'default',
  projectId: 'your-project-id',
  dataset: 'production',

  schema: {
    types: [
      /* document and object types */
    ],
  },

  plugins: [
    structureTool(),
    // Additional plugins...
  ],
})

Data flow architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                              SANITY STUDIO                               β”‚
β”‚                                                                         β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                 β”‚
β”‚  β”‚    Tool     β”‚    β”‚    Form     β”‚    β”‚   Preview   β”‚                 β”‚
β”‚  β”‚  Component  β”‚    β”‚   Builder   β”‚    β”‚   System    β”‚                 β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜                 β”‚
β”‚         β”‚                  β”‚                  β”‚                         β”‚
β”‚         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                         β”‚
β”‚                            β”‚                                            β”‚
β”‚                   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”                                   β”‚
β”‚                   β”‚  Document Store │◄─────── RxJS Observables          β”‚
β”‚                   β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                   β”‚
β”‚                            β”‚                                            β”‚
β”‚         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                         β”‚
β”‚         β”‚                  β”‚                  β”‚                         β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”                  β”‚
β”‚  β”‚   Mutator   β”‚   β”‚    Client    β”‚   β”‚  Listener   β”‚                  β”‚
β”‚  β”‚  (patches)  β”‚   β”‚   (queries)  β”‚   β”‚ (real-time) β”‚                  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜                  β”‚
β”‚         β”‚                  β”‚                  β”‚                         β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
          β”‚                  β”‚                  β”‚
          β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                             β”‚
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚  Content Lake   β”‚  (Sanity's hosted backend)
                    β”‚   (HTTP/WS)     β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Query flow

  1. Component requests data via hooks (useDocumentStore, useClient)
  2. Document Store manages subscriptions and caching
  3. Client sends GROQ queries to Content Lake
  4. Real-time listeners push updates back

Mutation flow

  1. User edits trigger form changes
  2. Form builder generates patches
  3. Mutator applies patches optimistically
  4. Mutations sent to Content Lake
  5. Confirmation/conflict resolution

Module organization

The main sanity package is organized into modules:
packages/sanity/src/
β”œβ”€β”€ core/                    # Core functionality
β”‚   β”œβ”€β”€ config/             # Configuration system
β”‚   β”œβ”€β”€ form/               # Form builder
β”‚   β”œβ”€β”€ hooks/              # React hooks
β”‚   β”œβ”€β”€ preview/            # Document preview
β”‚   β”œβ”€β”€ schema/             # Schema utilities
β”‚   β”œβ”€β”€ store/              # Data stores
β”‚   β”œβ”€β”€ studio/             # Studio shell components
β”‚   └── ...
β”œβ”€β”€ router/                  # Client-side routing
β”œβ”€β”€ structure/              # Structure tool
β”œβ”€β”€ presentation/           # Presentation tool
└── _exports/               # Public API exports

Entry points

The sanity package exposes multiple entry points:
ImportDescription
sanityMain exports (defineConfig, components, hooks)
sanity/structureStructure tool and builder
sanity/routerRouting utilities
sanity/presentationPresentation tool

Key technologies

TechnologyPurpose
ReactUI component framework
TypeScriptType safety and developer experience
RxJSReactive data streams and state management
ViteDevelopment server and build tool
GROQQuery language for Content Lake
Portable TextRich text data structure
@sanity/uiDesign system components
For more details on the monorepo structure and development workflow, see the ARCHITECTURE.md file in the repository.

Build docs developers (and LLMs) love