
Sanity CMS Gids: Hoe We in 10 Talen Publiceren
We hebben meer dan 400 stukken content gepubliceerd op 4 websites en in 10 talen via Sanity CMS. Dit is wat we hebben geleerd — van schemaontwerp tot geautomatiseerde meertalige publicatie.
Sanity CMS is een headless contentplatform dat is opgebouwd rondom gestructureerde content, een realtime Content Lake en een aanpasbare React-editor genaamd Sanity Studio. Het gebruikt GROQ voor queries, Portable Text voor rijke content en schema-as-code voor contentmodellering. Deze gids behandelt setup, schemaontwerp, GROQ, Portable Text, meertalige architectuur en prijzen.
Wat Is Sanity CMS?
Sanity is een gestructureerd contentplatform — wat het team bij Sanity.io een "content operating system" noemt. In tegenstelling tot traditionele CMS-en die HTML-blobs in een database opslaan, slaat Sanity elke stuk content op als gestructureerde JSON in een beheerde backend genaamd de Content Lake. Je bevraagt het met GROQ of GraphQL en rendert de content in elk gewenst frontend: Next.js, React Native, Svelte, een mobiele app, een CLI-tool — wat je maar wilt.
De bedrijven die het gebruiken lopen uiteen. Nike, Figma, Puma en Cloudflare draaien Sanity op enterprise-schaal. Startups gebruiken het omdat de gratis laag écht bruikbaar is (meer over prijzen verderop). Wij gebruiken het omdat niets anders ons de flexibiliteit gaf om een volledig geautomatiseerde pipeline voor 10 talen te bouwen.
Content Lake-architectuur
De Content Lake is Sanity's beheerde backend. Zie het als een gehoste documentopslag die in realtime synchroniseert over alle verbonden clients. Als een redacteur een alinea wijzigt in Sanity Studio, ziet een andere redacteur dat meteen — geen sla-knop, geen merge-conflicten, geen databasemigraties.
Onder de motorkap worden documenten opgeslagen als gestructureerde JSON met getypte velden. Elke mutatie wordt bijgehouden via een transactielogboek, waardoor je standaard volledige versiegeschiedenis krijgt. De realtime-synchronisatie gebruikt een listener-gebaseerde architectuur (beschreven in Sanity's GitHub-architectuurdocumentatie) die wijzigingen naar alle abonnees pusht via RxJS-observables.
Wat maakt dit anders dan, zeg, een PostgreSQL-database met een REST-API? De Content Lake regelt contentmodellering, toegangsbeheer, CDN-caching, afbeeldingstransformaties en realtime samenwerking als één beheerde dienst. Je voert geen migraties uit. Je beheert geen replica's. Je definieert gewoon schema's en bevraagt content.
Sanity Studio: Je Aanpasbare Editor
Sanity Studio is een open-source React-applicatie die als bewerkingsinterface dient. Het is geen gehoste adminpaneel — het is een React-app die in je codebase leeft. Je kunt elk aspect ervan aanpassen: aangepaste input-componenten, voorwaardelijke velden, documentacties, structure builder-patronen en plugins.
Realtime samenwerking is ingebouwd. Meerdere redacteuren kunnen gelijktijdig aan hetzelfde document werken, met aanwezigheidsindicatoren en live updates. Als je Google Docs ooit hebt gebruikt, is de ervaring vergelijkbaar — je ziet de cursors en wijzigingen van anderen in realtime.
We deployen onze Studio met npx sanity deploy, waarmee deze op Sanity's CDN wordt gehost op een aangepast subdomein. Je kunt hem ook zelf hosten omdat het gewoon een React-app is. We rangschikten Sanity hoog in onze headless CMS-vergelijking grotendeels vanwege de flexibiliteit van Studio.
Hoe Je een Sanity-project Instelt
Om Sanity CMS te installeren, installeer je de CLI met npm create sanity@latest, kies je een projecttemplate, configureer je je schemabestanden en voer je npx sanity dev uit om Studio lokaal te starten. Het hele proces duurt minder dan 5 minuten.
Vereisten en Installatie
Je hebt Node.js 18+ en npm (of pnpm) nodig. Dat is alles. Voer het init-commando uit:
npm create sanity@latest
# Je wordt gevraagd naar:
# - Inlogmethode (Google, GitHub, e-mail)
# - Projectnaam
# - Dataset-naam (standaard: "production")
# - Projecttemplate (blog, ecommerce, clean)
# - TypeScript? (aanbevolen: ja)De CLI bouwt een project met alles wat je nodig hebt. Zo ziet de projectstructuur eruit:
Projectstructuur Uitgelegd
my-sanity-project/
├── schemas/ # Je contentschema's (hier zul je de meeste tijd doorbrengen)
│ ├── index.ts # Schemaregister — importeert en exporteert alle typen
│ ├── post.ts # Documenttype-definities
│ └── blockContent.ts # Rich text / Portable Text-configuratie
├── sanity.config.ts # Hoofdconfiguratie — plugins, Studio-structuur, dataset
├── sanity.cli.ts # CLI-configuratie — project-ID, dataset
├── package.json
└── tsconfig.jsonHet sanity.config.ts-bestand is je startpunt. Hier is een minimale versie:
// sanity.config.ts
import { defineConfig } from 'sanity'
import { structureTool } from 'sanity/structure'
import { visionTool } from '@sanity/vision'
import { schemaTypes } from './schemas'
export default defineConfig({
name: 'default',
title: 'My Blog',
projectId: 'your-project-id',
dataset: 'production',
plugins: [structureTool(), visionTool()],
schema: { types: schemaTypes },
})De visionTool()-plugin geeft je een GROQ-speelplaats binnen Studio — je zult hem constant gebruiken tijdens de ontwikkeling.
Je Studio Deployen
Start lokaal met npx sanity dev (draait op localhost:3333). Als je klaar bent om het met redacteuren te delen, deploy je naar Sanity's CDN:
npx sanity deploy
# Vraagt om een hostnaam, bijv. "my-blog"
# Deployt naar https://my-blog.sanity.studioPro-tip: voer npx sanity@latest schema deploy uit na elke schemawijziging. Dit uploadt je schema naar Sanity's API, waarmee functies zoals de GraphQL-API en schema-bewuste tooling worden ingeschakeld (inclusief de MCP-server die we later behandelen).
Schemaontwerp in Sanity CMS
Sanity-schema's worden gedefinieerd als JavaScript- of TypeScript-objecten in je codebase. Elk schema specificeert een documenttype met velden, validatieregels en aangepaste input-componenten. Wijzigingen in schema's zijn onmiddellijk van kracht — er zijn geen databasemigraties vereist. Dit is de "schema-as-code"-aanpak, en het is wat ons overtuigde om voor Sanity te kiezen in plaats van Contentful.
Veldtypen en Validatie
Sanity wordt geleverd met een uitgebreide set veldtypen. Dit zijn de typen die we het meest gebruiken:
| Veldtype | Gebruiksscenario | Voorbeeld |
|---|---|---|
string | Korte tekst, titels, slugs | Berichttitel, auteursnaam |
text | Meerdere regels platte tekst | Uittreksels, beschrijvingen |
number | Gehele getallen, kommagetallen | Leestijd, sorteervolgorde |
boolean | Schakelaars | Uitgelicht-vlag, conceptstatus |
array | Lijsten, rich text (Portable Text) | Berichtinhoud, tags |
reference | Verwijzingen naar andere documenten | Auteur, categorie |
image | Afbeeldingen met metadata | Omslagafbeelding met alt-tekst |
slug | URL-vriendelijke strings | Automatisch gegenereerd vanuit titel |
object | Geneste veldgroepen | SEO-velden (metaTitle + metaDescription) |
date / datetime | Datums | Publicatiedatum |
Elk veld ondersteunt validatie via een validation-callback. Je kunt verplichte velden, min/max-waarden, regex-patronen en aangepaste regels afdwingen:
defineField({
name: 'seoDescription',
title: 'Meta Description',
type: 'string',
validation: (Rule) =>
Rule.required()
.min(145)
.max(160)
.warning('Meta description should be 145-160 characters'),
})Aangepaste Bloktypen (Onze Productievoorbeelden)
Hier wordt Sanity interessant — en hier laten 0 van de 6 concurrerende gidsen geen code zien. In ons productieschema definiëren we vijf aangepaste bloktypen binnen de body-array: block (standaardtekst), table, codeBlock, chartBlock en inlineImage.
Hier is onze codeBlock-definitie:
// schemas/objects/codeBlock.ts
import { defineType } from 'sanity'
export const codeBlock = defineType({
name: 'codeBlock',
title: 'Code Block',
type: 'object',
fields: [
{
name: 'language',
title: 'Language',
type: 'string',
options: {
list: [
{ title: 'JavaScript', value: 'javascript' },
{ title: 'TypeScript', value: 'typescript' },
{ title: 'Python', value: 'python' },
{ title: 'Bash', value: 'bash' },
{ title: 'JSON', value: 'json' },
{ title: 'GROQ', value: 'groq' },
],
},
},
{
name: 'code',
title: 'Code',
type: 'text',
},
],
})En zo verwijst het body-veld naar al onze aangepaste typen samen:
// schemas/fields/body.ts
defineField({
name: 'body',
title: 'Body',
type: 'array',
of: [
{ type: 'block' }, // Standaard Portable Text (alinea's, koppen, lijsten)
{ type: 'table' }, // @sanity/table plugin
{ type: 'codeBlock' }, // Onze aangepaste codeblok
{ type: 'chartBlock' }, // Datavisualisatie (staaf-, lijn-, cirkeldiagram)
{ type: 'inlineImage' }, // Afbeeldingen met alt-tekst en bijschriften
],
})Dit geeft onze redacteuren een rijke contenttoolkit terwijl elk element getypt en bevraabaar blijft. Een chartBlock is niet zomaar een ondoorzichtige HTML-embed — het is gestructureerde data met velden voor chartType, title, dataPoints en dataLabels. Dat telt als je dezelfde content wilt renderen op web, e-mail en mobiel.
Best Practices voor Schema-organisatie
Houd schema's modulair. Wij splitsen de onze op in bestanden per type: schemas/documents/post.ts, schemas/objects/codeBlock.ts, schemas/objects/chartBlock.ts. Importeer ze allemaal in schemas/index.ts:
// schemas/index.ts
import { post } from './documents/post'
import { codeBlock } from './objects/codeBlock'
import { chartBlock } from './objects/chartBlock'
import { inlineImage } from './objects/inlineImage'
export const schemaTypes = [post, codeBlock, chartBlock, inlineImage]Het belangrijkste inzicht dat we hebben opgedaan door met gestructureerde content te werken: je schema IS je contentmodel. Als je het ziet als context engineering voor je contentteam, maak je betere ontwerpbeslissingen. Elk veld dat je toevoegt moet een doel dienen — voor redacteuren, voor rendering of voor queries.
GROQ: Sanity's Querytaal
GROQ (Graph-Relational Object Queries) is Sanity's open-source querytaal voor het filteren, samenvoegen en projecteren van JSON-documenten. De basissyntaxis is *[filter]{projection} — selecteer alle documenten die overeenkomen met een filter en geef de uitvoer de gewenste vorm. Het is beknopter dan GraphQL voor Sanity-specifieke queries en, in onze ervaring, sneller te leren.
Basisqueries: Filteren en Projecteren
De eenvoudigste query haalt alle documenten van een type op:
// Haal alle berichten op — alleen titel en slug
*[_type == "post"]{
title,
"slug": slug.current
}
// Filter op taal, vouw auteurverwijzing uit
*[_type == "post" && language == "en"]{
title,
"slug": slug.current,
"authorName": author->name,
"authorImage": author->image,
"categoryTitle": category->title,
publishedAt
}De -> operator volgt verwijzingen. author->name betekent "volg de auteurverwijzing en geef het naamveld terug." Geen afzonderlijke queries, geen N+1-problemen, geen JOINs — het is allemaal één expressie.
Joins, Ordening en Paginering
Voor onze blogindexpagina's hebben we geordende, gepagineerde berichten nodig met uitgevouwen verwijzingen:
// Gepagineerde berichten met volledige metadata
*[_type == "post" && language == "en"] | order(publishedAt desc) [0...10] {
title,
"slug": slug.current,
excerpt,
publishedAt,
readTime,
"author": author->{name, image},
"category": category->{title, "slug": slug.current},
"coverImage": coverImage{
"src": asset->url,
alt
}
}[0...10] geeft je de eerste 10 resultaten (0-geïndexeerd, exclusief einde). | order(publishedAt desc) sorteert op nieuwste eerst. De projectie geeft de uitvoer precies de vorm die je frontend nodig heeft — niet meer.
Je kunt al deze queries interactief testen met de Vision-plugin binnen Sanity Studio. Onmisbaar tijdens de ontwikkeling. Bekijk voor meer patronen het GROQ cheat sheet.
GROQ vs GraphQL
Sanity ondersteunt zowel GROQ als GraphQL. Wanneer gebruik je welke?
GROQ is Sanity's eigen taal. Het verwerkt joins, projecties en berekende velden in één querystring. Het is waarvoor de Content Lake geoptimaliseerd is.
GraphQL is beschikbaar nadat je je schema deployt (npx sanity@latest schema deploy). Gebruik het als je gestandaardiseerde tooling nodig hebt — bijvoorbeeld als je frontend al Apollo Client gebruikt, of als je team GraphQL kent maar geen GROQ.
Wij gebruiken uitsluitend GROQ. Het is expressiever voor Sanity-data en de Vision-plugin maakt het debuggen van queries eenvoudig.
Portable Text: Rijke Content Op de Juiste Manier
Portable Text is Sanity's specificatie voor gestructureerde rich text. In plaats van content op te slaan als HTML-strings, slaat het een array van getypte blokken op — alinea's, koppen, afbeeldingen, codefragmenten, tabellen — elk als een JSON-object. Dit maakt content renderbaar in elk framework, elk platform en elk formaat.
De Gegevensstructuur
Zo ziet een alinea en een codeblok eruit als Portable Text-JSON:
[
{
"_type": "block",
"_key": "a1b2c3",
"style": "normal",
"markDefs": [],
"children": [
{
"_type": "span",
"_key": "d4e5f6",
"text": "Here's an example of our pipeline config:",
"marks": []
}
]
},
{
"_type": "codeBlock",
"_key": "g7h8i9",
"language": "typescript",
"code": "export default defineConfig({ ... })"
}
]Elk blok heeft een _type en een _key. Standaardtekstblokken gebruiken "block" met child spans (die marks ondersteunen zoals vet, cursief en links). Aangepaste blokken — zoals onze codeBlock, chartBlock, table en inlineImage — gebruiken hun eigen _type en bevatten gestructureerde velden.
Waarom maakt dit uit? Omdat HTML een renderformaat is, geen opslagformaat. Als je <h2>Titel</h2><p>Wat <strong>tekst</strong></p> in je database opslaat, zit je vast aan webrendering. Je kunt dat niet schoon extraheren voor een mobiele app, een e-mailnieuwsbrief, een PDF of het contextvenster van een AI-agent. Portable Text scheidt content van presentatie. De Portable Text-specificatie is open source — het is geen Sanity-lock-in.
Aangepaste Blokken in Productie
Onze pipeline converteert Markdown naar Portable Text met een Python-script (scripts/md_to_portable_text.py). De converter verwerkt standaardblokken, plus onze vier aangepaste typen:
table— gebruikt het@sanity/table-pluginschema. Rijen en cellen opgeslagen als gestructureerde data.codeBlock— taal en code als afzonderlijke velden, waardoor syntaxiskleuring bij rendering mogelijk wordt.chartBlock— diagramtype, titel, aslabels, serienamen en datapunten als gestructureerde JSON. De frontend rendert deze met Chart.js.inlineImage— alt-tekst, bron en optioneel bijschrift als afzonderlijke velden.
Deze structuur betekent dat we via GROQ kunnen zoeken naar alle codevoorbeelden in onze blog (*[body[]._type == "codeBlock"]), berichten met diagrammen kunnen vinden of alle afbeeldingen met ontbrekende alt-tekst kunnen extraheren.
Portable Text Renderen
Gebruik op de frontend @portabletext/react (of de Svelte/Vue-equivalenten). Je registreert aangepaste componenten voor elk bloktype:
import { PortableText } from '@portabletext/react'
const components = {
types: {
codeBlock: ({ value }) => (
<pre className={`language-${value.language}`}>
<code>{value.code}</code>
</pre>
),
chartBlock: ({ value }) => <Chart data={value} />,
inlineImage: ({ value }) => (
<figure>
<img src={value.src} alt={value.alt} />
{value.caption && <figcaption>{value.caption}</figcaption>}
</figure>
),
},
}
// In je component:
<PortableText value={post.body} components={components} />Dat is de volledige renderingpipeline. De PortableText-component verwerkt standaardblokken (alinea's, koppen, lijsten, marks) automatisch. Je definieert alleen aangepaste componenten voor je aangepaste typen.
Meertalige Content met Sanity CMS
Sanity ondersteunt meertalige content via localisatie op documentniveau (afzonderlijke documenten per taal gekoppeld door een canonieke verwijzing) of localisatie op veldniveau (vertaalde velden binnen één document). Localisatie op documentniveau werkt beter voor SEO en grootschalige publicatie — dat is wat we gebruiken in onze pipeline voor 10 talen.
Localisatie op Documentniveau vs. Veldniveau
| Aspect | Documentniveau | Veldniveau |
|---|---|---|
| Aanpak | Afzonderlijk document per taal | Alle vertalingen in één document |
| SEO | Elk document heeft zijn eigen URL/slug | Één URL, moeilijker voor taalspecifieke pagina's |
| Querycomplexiteit | Eenvoudige filters: language == "de" | Geneste veldtoegang: title.de |
| Contentomvang | Kleine, gerichte documenten | Één groot document met alle talen |
| Het beste voor | Blogberichten, pagina's, SEO-gedreven content | Kleine UI-strings, labels, metadata |
| Ons oordeel | We gebruiken dit voor alles | Alleen voor gedeelde UI-strings |
We kozen voor localisatie op documentniveau omdat elke vertaling zijn eigen slug, zijn eigen URL en zijn eigen metadata krijgt. De Nederlandse versie van een bericht over Supabase vs Firebase krijgt de slug supabase-vs-firebase-vergelijking — normaal Nederlands, geen URL-parameter-hack.
Onze Pipeline-architectuur voor 10 Talen
Zo werkt onze geautomatiseerde pipeline: we schrijven een bericht in het Engels en vertalen het vervolgens naar 9 extra talen (Duits, Frans, Nederlands, Spaans, Turks, Italiaans, Zweeds, Noors, Arabisch). Elke vertaling doorloopt Markdown-conversie, Portable Text-generatie en Sanity API-publicatie.
De architectuur ziet er zo uit:
- Schrijven — Engelstalige Markdown met YAML-frontmatter
- Vertalen — AI-vertaling naar 9 talen (gecontroleerd op volledigheid en diakritische tekens)
- Converteren — Python-script converteert elk
.md-bestand naar Portable Text-JSON - Publiceren — API-aanroepen naar Sanity: document aanmaken, afbeeldingen uploaden, verwijzingen patchen
Elk document heeft een language-veld en een canonicalPost-verwijzing die naar het Engelse origineel wijst. Hier is de GROQ-query om een bericht en al zijn vertalingen op te halen:
// Haal een bericht op met al zijn vertalingen
*[_type == "post" && slug.current == "sanity-cms-guide" && language == "en"][0]{
title,
language,
"translations": *[
_type == "post" &&
canonicalPost._ref == ^._id
]{
title,
language,
"slug": slug.current
}
}De schemakant is eenvoudig — een language-veld met een enum van ondersteunde talen:
defineField({
name: 'language',
title: 'Language',
type: 'string',
options: {
list: [
{ title: 'English', value: 'en' },
{ title: 'German', value: 'de' },
{ title: 'French', value: 'fr' },
{ title: 'Dutch', value: 'nl' },
{ title: 'Spanish', value: 'es' },
{ title: 'Turkish', value: 'tr' },
{ title: 'Italian', value: 'it' },
{ title: 'Swedish', value: 'sv' },
{ title: 'Norwegian', value: 'no' },
{ title: 'Arabic', value: 'ar' },
],
},
validation: (Rule) => Rule.required(),
})Eén valkuil die we de harde manier hebben geleerd: publiceer het Engelse document eerst en patch daarna canonicalPost-verwijzingen op vertalingen met het gepubliceerde document-ID — niet het drafts.-voorvoegsel. Sanity behandelt concept- en gepubliceerde documenten intern als afzonderlijke entiteiten.
Zie voor meer details over hoe deze pipeline verbinding maakt met het Model Context Protocol de volgende sectie.
Sanity AI-functies: MCP, Canvas en Agent Context
Sanity positioneert zich als het content operating system voor het AI-tijdperk. Belangrijke AI-functies zijn onder andere een MCP-server waarmee AI-agents content kunnen lezen en schrijven, Canvas voor AI-ondersteunde bewerking binnen Studio en Agent Context voor productie-AI-agents om gestructureerde content met schema-bewustheid te bevragen.
MCP-serverintegratie
De Sanity MCP-server laat AI-agents — Claude Code, Cursor, Windsurf en anderen — programmatisch met je Sanity-workspace communiceren. Agents kunnen schema's lezen, GROQ-queries uitvoeren, documenten aanmaken en content beheren zonder aangepaste API-wrappers.
We gebruiken de Sanity MCP-server dagelijks in onze contentpipeline. Onze AI-agents bevragen het schema om de documentstructuur te begrijpen, halen bestaande berichten op om interne linkmogelijkheden te vinden en publiceren nieuwe documenten. Het MCP-protocol geeft agents schema-bewustheid — ze weten welke velden er bestaan, welke typen ze verwachten en welke validatieregels van toepassing zijn. Als je AI-agents voor bedrijven workflows bouwt, is dit een krachtig patroon.
Agent Context voor Productie-AI
Agent Context is een afzonderlijke functie voor AI-integraties op productieschaal. In tegenstelling tot de MCP-server (die is ontworpen voor ontwikkelaarstools), biedt Agent Context alleen-lezen, afgebakende toegang voor AI-agents die je content tijdens runtime moeten bevragen — denk aan chatbots, aanbevelingsengines of contentpersonalisatiesystemen.
Het verschil is belangrijk: MCP is voor build-time- en redactionele workflows (schema-bewuste ontwikkeltools), terwijl Agent Context is bedoeld voor runtime-contenttoegang met goede authenticatie en rate limiting.
Sanity's gestructureerde content geeft het hier een echt voordeel. Een WordPress-site slaat content op als HTML-blobs — een AI-agent moet HTML parsen om de content te begrijpen. Sanity slaat getypte JSON-documenten op met gedefinieerde schema's. Een agent kan *[_type == "product" && category == "electronics"]{name, price, features} bevragen en schone, gestructureerde data terugkrijgen. Geen scraping, geen parsing, geen gissen.
Hoe We Sanity bij Techsy Gebruiken
Dit is geen hypothetische sectie. We draaien Sanity CMS op 4 productiewebsites en publiceren in 10 talen met een geautomatiseerde pipeline die we het afgelopen jaar hebben gebouwd. Hier is de architectuur.
Onze Contentpipeline-architectuur
De pipeline loopt van onderzoek tot gepubliceerd bericht in alle 10 talen:
- Onderzoek — trefwoordanalyse, identificatie van concurrentieleemtes, SERP-patronen
- Briefing — gestructureerde schrijfspecificatie met sectiebegeleiding, woordaantallen, interne links
- Schrijven — Engelstalige Markdown met YAML-frontmatter produceren
- Converteren — Python-script transformeert Markdown naar Portable Text-JSON met onze 5 aangepaste bloktypen
- Publiceren — API-aanroepen naar Sanity:
createOrReplace-document, afbeeldingen uploaden naar Sanity CDN, auteur/categorieverwijzingen patchen - Vertalen — AI-vertaling naar 9 talen, gecontroleerd op volledigheid
- Vertalingen publiceren — zelfde converteer/publiceerflow per taal, met
canonicalPost-verwijzing gepatcht naar het Engelse origineel
Het aangepaste schema ondersteunt de typen block, table, codeBlock, chartBlock en inlineImage — allemaal gedefinieerd als productie-Sanity-schemaobjecten met validatieregels. Onder de AI-tools voor startups die we hebben getest, is deze op Sanity gebaseerde pipeline de meest betrouwbare gebleken voor gestructureerde content op schaal.
Lessen uit 400+ Gepubliceerde Stukken
Een paar dingen die we hadden gewild dat iemand ons had verteld:
De volgorde van het patchen van verwijzingen doet ertoe. Sanity-verwijzingen kunnen niet naar documenten wijzen die nog niet bestaan. Publiceer het Engelse bericht eerst en maak dan vertalingen met canonicalPost die wijst naar het gepubliceerde ID van het Engelse document. We hebben dit in het begin meerdere keren verkeerd gedaan.
Schema-deployment is per workspace. Als je meerdere Sanity-projecten beheert (wij beheren er 4), moet je schema's afzonderlijk deployen naar elk project: npx sanity@latest schema deploy per projectconfiguratie.
De gratis laag is echt. We hebben twee van onze vier sites maandenlang op het gratis plan gedraaid. 20 gebruikers, 500K API-aanvragen per maand, 100K CDN-aanvragen — dat is genoeg voor een echte productiesite, niet alleen een speelproject.
Portable Text-conversie is het knelpunt. Markdown naar Portable Text is niet triviaal. Geneste lijsten, tabellen binnen blockquotes, codeblokken met speciale tekens — overal randgevallen. We hebben maandenlang aan ons conversiescript gewerkt.
Hulp nodig bij het instellen van Sanity voor je project? We hebben meertalige contentpipelines gebouwd voor 4 productiesites. Vraag een gratis consult aan
Sanity CMS Prijsoverzicht
Sanity biedt drie abonnementen: Gratis (20 gebruikers, 500K API-aanvragen per maand), Growth ($15 per gebruiker per maand met geavanceerde rollen en geplande concepten) en Enterprise (aangepaste prijzen met SLA en compliancefuncties). De gratis laag is de meest royale op de headless CMS-markt.
| Functie | Gratis | Growth ($15/gebruiker/mo) | Enterprise |
|---|---|---|---|
| Gebruikers | 20 | 50 | Onbeperkt |
| API-aanvragen | 500K/maand | 2,5M/maand | Aangepast |
| CDN-aanvragen | 100K/maand | 500K/maand | Aangepast |
| Rollen | Alleen admin | Admin, Developer, Editor, Contributor | Aangepaste rollen |
| Samenwerking | Realtime bewerken | + Geplande publicatie, concepten | + Workflows |
| Ondersteuning | Community | Dedicated + SLA | |
| Compliance | — | — | SOC 2, HIPAA |
Op de gratis laag draaien we twee van onze sites zonder limieten te bereiken. Het Growth-abonnement voor $15 per gebruiker per maand voegde rolgebaseerde toegang toe (belangrijk zodra we niet-technische redacteuren hadden) en geplande publicatie. Kijkers zijn gratis op Growth — je wordt niet gestraft voor het geven van leestoegang aan stakeholders.
Hoe vergelijkt dit met concurrenten?
| Functie | Sanity Gratis | Contentful Gratis | Strapi Cloud Gratis | Payload Cloud |
|---|---|---|---|---|
| Gebruikers | 20 | 1 | 1 | 1 |
| Contenttypen | Onbeperkt | 48 | Onbeperkt | Onbeperkt |
| API-aanroepen | 500K/mo | Inbegrepen | Inbegrepen | Inbegrepen |
| Aangepaste typen | Ja | Beperkt | Ja | Ja |
| Prijs om te groeien | $15/gebruiker/mo | $300/mo | $29/mo | $50/mo |
Sanity's gratis laag van 20 gebruikers is uitzonderlijk. Contentful beperkt je op gratis tot 1 gebruiker en springt naar $300 per maand voor hun Team-abonnement. Als je een startup of klein team bent, laat Sanity's gratis abonnement je echte productie-workloads draaien zonder iets uit te geven.
Sanity biedt ook een startup-programma dat in aanmerking komende startups één jaar gratis Growth-toegang geeft. De moeite waard om voor aan te vragen als je in aanmerking komt.
Veelgestelde Vragen
Wat is Sanity CMS en hoe werkt het?
Sanity CMS is een headless contentplatform dat gestructureerde JSON-documenten opslaat in een beheerde backend genaamd de Content Lake. Je bewerkt content via Sanity Studio (een aanpasbare React-app), bevraagt het met GROQ of GraphQL en rendert het in elk frontend-framework. Content synchroniseert in realtime over alle verbonden clients.
Is Sanity CMS gratis?
Ja. De gratis laag van Sanity omvat 20 gebruikers, 500K API-aanvragen per maand en 100K CDN-aanvragen — het meest royale gratis abonnement onder headless CMS-platforms. Het Growth-abonnement kost $15 per gebruiker per maand en voegt rolgebaseerde toegang, geplande publicatie en hogere limieten toe. Enterprise-prijzen zijn op maat.
Wat is het verschil tussen Sanity en Contentful?
Sanity gebruikt schema-as-code (schema's leven in je codebase), GROQ voor queries en een volledig aanpasbare open-source Studio. Contentful gebruikt GUI-gebaseerde contentmodellering, GraphQL en een gehoste editor met minder aanpassing. Sanity's gratis laag omvat 20 gebruikers tegenover Contentful's 1. Contentful heeft een groter plugin-ecosysteem.
Is Sanity CMS geschikt voor beginners?
Sanity Studio is intuïtief voor contentredacteuren — de bewerkingservaring vereist geen technische kennis. Het instellen van schema's vereist echter vaardigheid in JavaScript of TypeScript. Sanity biedt uitstekende documentatie, projecttemplates en een community Slack met actieve ondersteuning. Begin met npm create sanity@latest en een blogtemplate.
Kan ik Sanity zelf hosten?
Sanity Studio is volledig zelf te hosten omdat het een open-source React-applicatie is. Je kunt het deployen op Vercel, Netlify of elke statische hostingprovider. De Content Lake-backend is een beheerde dienst — er is geen self-hosting optie voor de datalaag. Dit is een afweging: je krijgt nul infrastructuurbeheer maar geen on-premises datacontrole.
Welk type database gebruikt Sanity?
Sanity's Content Lake is geen traditionele SQL- of NoSQL-database. Het is een beheerde documentopslag die content opslaat als gestructureerde JSON met een GROQ-querylaag erop. Je communiceert niet direct met de onderliggende database — je communiceert via Sanity's API's. Documenten hebben standaard volledige versiegeschiedenis en realtime synchronisatie ingebouwd.
Is Sanity CMS open source?
Sanity Studio is open source onder de MIT-licentie — je kunt het forken, aanpassen en zelf hosten. De Content Lake-backend is propriëtaire SaaS. De GROQ-querytaalspecificatie is ook open source, gepubliceerd op GitHub. De Portable Text-specificatie is eveneens open source en wordt beheerd op portabletext.org.
Wat is Portable Text in Sanity?
Portable Text is Sanity's specificatie voor gestructureerde rich text. In plaats van content op te slaan als HTML-strings, stelt het alinea's, koppen, afbeeldingen en aangepaste blokken voor als getypte JSON-objecten in een array. Dit maakt content portabel over frameworks en platforms. Je kunt aangepaste bloktypen definiëren zoals codefragmenten, diagrammen en tabellen met hun eigen gestructureerde velden.
Wat is GROQ en hoe verschilt het van GraphQL?
GROQ (Graph-Relational Object Queries) is Sanity's eigen querytaal. De syntaxis — *[filter]{projection} — is beknopter dan GraphQL voor Sanity-data, met ingebouwde ondersteuning voor joins via de -> operator en berekende velden. GraphQL is ook beschikbaar voor teams die gestandaardiseerde tooling verkiezen of al Apollo Client gebruiken.
Hoe gaat Sanity om met meertalige content?
Sanity ondersteunt localisatie op documentniveau (afzonderlijke documenten per taal gekoppeld door canonieke verwijzingen) en localisatie op veldniveau (vertaalde velden binnen één document). Localisatie op documentniveau is beter voor SEO omdat elke vertaling zijn eigen URL en metadata krijgt. Wij gebruiken localisatie op documentniveau om in 10 talen te publiceren met geautomatiseerde vertaal- en publicatiepipelines.