Type something to search...
Why Developers Love Sanity: Key Features Explained

Why Developers Love Sanity: Key Features Explained

Developers love Sanity because it treats content as structured data that you control with code. You define schemas in TypeScript, query them with GROQ, store rich text as portable JSON, customise the editing app with React, and generate types for your frontend, all while Sanity runs the hosted backend for you. The result is a CMS that fits into a normal developer workflow of Git, pull requests and typed code, instead of one that asks you to click through settings screens or maintain a server.

That's a strong claim, and it's worth seeing what's behind it. This article explains the features developers point to most often: schema-as-code, GROQ, the Content Lake, Portable Text, a customisable Studio, real-time collaboration, TypeGen, the image pipeline, visual editing, webhooks and functions, and a free tier that's useful for real projects. Each section includes a short example so you can judge for yourself.

1. Schema as Code

In Sanity, your content model is TypeScript, not configuration stored in a database:

// schemaTypes/product.ts
import { defineField, defineType } from 'sanity';

export const product = defineType({
  name: 'product',
  title: 'Product',
  type: 'document',
  fields: [
    defineField({ name: 'name', type: 'string', validation: (rule) => rule.required() }),
    defineField({ name: 'price', type: 'number', validation: (rule) => rule.positive() }),
    defineField({
      name: 'onSale',
      type: 'boolean',
      initialValue: false,
    }),
    defineField({
      name: 'salePrice',
      type: 'number',
      hidden: ({ document }) => !document?.onSale,
    }),
  ],
});

Why this matters to developers:

  • Version control: model changes go through Git and code review like everything else.
  • Reuse: you can import shared field definitions, write helper functions that build fields, and share types across projects.
  • Logic where you need it: validation, conditional fields and initial values are plain JavaScript functions.
  • Autocomplete: defineType and defineField give you type hints for every option in your editor.

If you want to try it, follow how to create your first schema in Sanity.

2. GROQ: Ask for Exactly What You Need

GROQ (Graph-Relational Object Queries) is Sanity's query language. A single query can filter, sort, slice, follow references and reshape the result:

*[_type == "product" && onSale]
  | order(salePrice asc)[0...5]{
    name,
    "price": salePrice,
    "category": category->title,
    "image": mainImage.asset->url
  }

Developers like GROQ because it removes a lot of glue code. You don't need a resolver layer or multiple round trips, and the response comes back in the shape your component wants. You can test queries live in Studio with the Vision tool. The GROQ explainer covers the syntax from scratch.

3. A Schemaless Content Lake

Sanity stores your content in the Content Lake, a hosted document store. It's schemaless: the Studio schema decides what editors see and validates their input, but the stored documents are just JSON. That has practical benefits:

  • Adding fields needs no migration: new fields simply start appearing on documents as editors fill them in.
  • Any JSON is queryable: data you import with scripts is immediately available to GROQ.
  • Drafts, versions and history: the Content Lake keeps drafts separate from published documents and tracks changes, so you get revision history without building it.

The trade-off is that you need to be careful when renaming fields, because old documents keep the old data until you migrate them. Read Sanity Content Lake explained for how drafts and perspectives work.

4. Portable Text for Rich Content

Rich text in Sanity is stored as Portable Text, a JSON array of blocks and custom objects, rather than HTML. That means you can render the same content on a website, in a mobile app or in an email, and embed your own types such as call-outs or code samples right in the text.

Rendering it in React is a small component:

import { PortableText, type PortableTextComponents } from '@portabletext/react';

const components: PortableTextComponents = {
  types: {
    callout: ({ value }) => <aside className="callout">{value.text}</aside>,
  },
  marks: {
    link: ({ children, value }) => <a href={value.href}>{children}</a>,
  },
};

export function Body({ value }: { value: any[] }) {
  return <PortableText value={value} components={components} />;
}

No HTML parsing, no dangerouslySetInnerHTML and no sanitising. You decide how every block renders. See what is Portable Text for the structure.

5. A Studio You Can Shape

Sanity Studio is an open-source React application that lives in your repository. You configure it in sanity.config.ts:

// sanity.config.ts
import { defineConfig } from 'sanity';
import { structureTool } from 'sanity/structure';
import { visionTool } from '@sanity/vision';
import { schemaTypes } from './schemaTypes';

export default defineConfig({
  name: 'default',
  title: 'Shop',
  projectId: 'your-project-id',
  dataset: 'production',
  plugins: [
    structureTool({
      structure: (S) =>
        S.list()
          .title('Content')
          .items([
            S.documentTypeListItem('product').title('Products'),
            S.divider(),
            ...S.documentTypeListItems().filter((item) => item.getId() !== 'product'),
          ]),
    }),
    visionTool(),
  ],
  schema: { types: schemaTypes },
});

From there you can add custom input components, document actions, badges, entire custom tools and plugins from npm. You can run Studio on its own, deploy it to Sanity's hosting, or embed it in a route of your Next.js app. The Studio walkthrough shows what editors get out of the box.

6. Real-Time Collaboration

Multiple editors can work in the same document at once. Changes sync instantly, avatars show who's in which field, and every change is recorded in the history so you can see what changed and restore older versions. Developers appreciate this because they don't have to build locking, conflict resolution or audit trails.

The same real-time foundation powers live queries. With next-sanity, you can have pages update as soon as content is published, without a rebuild.

7. Generated TypeScript Types

Sanity TypeGen generates types from your schema and your GROQ queries, so your frontend knows the exact shape of each query result:

npx sanity schema extract
npx sanity typegen generate

Wrap queries with defineQuery so TypeGen can find them:

import { defineQuery } from 'next-sanity';

export const PRODUCT_QUERY = defineQuery(`*[_type == "product" && _id == $id][0]{
  name,
  price
}`);

TypeGen writes sanity.types.ts, including a result type for each query. When you change a field name in the schema, your frontend fails type-checking in the places that need updating, instead of failing at runtime. You can configure it in the typegen block of sanity.cli.ts and enable automatic generation during development.

8. A Built-In Image Pipeline

Every uploaded image is served from Sanity's image CDN with transformations applied through URL parameters. Editors can set a hotspot and crop in Studio, and the URL builder respects them:

import { createImageUrlBuilder } from '@sanity/image-url';
import { client } from './client';

const builder = createImageUrlBuilder(client);

export function urlFor(source: Parameters<typeof builder.image>[0]) {
  return builder.image(source);
}

// urlFor(product.mainImage).width(800).height(800).fit('crop').auto('format').url()

You get resizing, cropping, format conversion and quality control without running an image service. Image assets also carry metadata such as dimensions, a blurred placeholder (LQIP) and the dominant colour palette, which you can query with GROQ. See the image URL builder guide for more.

9. Visual Editing and Previews

Sanity's Presentation tool shows your actual website inside Studio, with click-to-edit overlays that jump from the page to the right field. In a Next.js App Router project, next-sanity provides the pieces for draft mode, live content and overlays. Editors get confidence in what they publish, and developers get a supported setup instead of a home-made preview system.

10. Webhooks and Functions

Sanity's webhooks use GROQ for both the filter and the payload. You can fire a webhook only when a published product changes price, and send just the fields your endpoint needs:

_type == "product" && delta::changedAny(price)

For logic that should run near your content, Sanity Functions run serverless code in response to document events on Sanity's infrastructure. Typical uses include generating summaries, syncing to a search index or notifying a team channel.

11. Developer-Friendly Tooling

A few smaller things add up to a pleasant workflow:

  • One CLI: npx sanity handles dev, build, deploy, dataset import and export, CORS origins, tokens and more. See essential Sanity CLI commands.
  • Typed clients: @sanity/client and next-sanity are written in TypeScript and work in Node.js, edge runtimes and browsers.
  • Datasets for environments: create a staging dataset, test schema and content changes, then move on.
  • Starters and templates: npm create sanity@latest can scaffold a clean project or a template with a frontend.

12. A Free Plan You Can Ship On

Sanity's Free plan includes up to 20 seats, two public datasets, 10,000 documents and generous monthly API and CDN quotas, which is enough for many personal sites, portfolios and small business sites in production. The Growth plan is priced per seat, and viewer seats are free on every plan. The pricing guide explains where the limits sit.

Where Developers Push Back

No tool is perfect, and it's fair to know the common criticisms:

CriticismWhat it means in practice
Learning GROQA new query language to learn, though the basics take an afternoon
Validation only in StudioAPI writes skip schema validation, so scripts must validate their own data
Developer needed for model changesEditors can't add content types themselves
Usage-based costsHigh-traffic sites must watch API and bandwidth overages, usually solved with caching

For developer-led teams, these are usually acceptable trade-offs. For editor-led teams who want to change the model without code, they can be deal-breakers.


FAQ: Why Developers Love Sanity

Yes, if you're comfortable with basic JavaScript. You can create a project with one command and have a working Studio in minutes. The concepts that take longer are GROQ and Portable Text, but both are well documented and you can start with simple queries.

No. Sanity can deploy a GraphQL API generated from your schema, and you can also read documents by ID through the HTTP API. Most developers end up preferring GROQ because it can join and reshape data in a single query.

Yes. Sanity Studio is open source under the MIT licence and published on npm as the sanity package. The Content Lake that stores your data is a hosted service, but the editing app and its plugins are code you own and can customise.

Yes. Sanity is framework-agnostic, with official tooling and guides for Next.js, Astro, Nuxt, SvelteKit, Remix and others. Any language that can make HTTP requests can query the API.

Yes. Sanity TypeGen extracts your schema with sanity schema extract and then generates types for documents and GROQ query results with sanity typegen generate. Wrap queries with defineQuery so the generator can find them.

The most common complaints are learning GROQ, the fact that schema validation only runs in Studio, and usage-based overages on busy sites. Most teams manage these with documentation, validation in import scripts and caching through the API CDN or their framework.


Conclusion

Developers love Sanity because it fits the way they already work. Schemas live in Git, GROQ returns exactly the shape you need, Portable Text keeps rich content structured, TypeGen keeps the frontend honest, and the Studio is a React app you can bend around your editors. Meanwhile, the hosted Content Lake removes servers, databases and backups from your to-do list.

The best way to judge is to build something small. Set up a project, write a schema and query it from your frontend. Start with how to set up your first Sanity project, and you'll quickly see whether the workflow suits you.

Tags :
Share :

Related Posts

Building a Static Site With Astro and Sanity

Building a Static Site With Astro and Sanity

To build a static site with Astro and Sanity, keep Astro's default output: 'static', configure @sanity/astro with useCdn: false, and fetch

Dive Deeper
Common Sanity Mistakes and How to Fix Them

Common Sanity Mistakes and How to Fix Them

The most common Sanity mistakes are using the CDN where you need fresh data, fetching whole documents with ..., leaving slugs unvalidated, ship

Dive Deeper
How to Create a Custom Sanity Plugin

How to Create a Custom Sanity Plugin

To create a custom Sanity plugin, wrap a piece of Studio configuration in definePlugin from the sanity package and add it to the plugins ar

Dive Deeper