Waarom ik Hygraph inruilde voor Sanity

De kosten van talen, API-quota en een CMS dat agents kunnen aansturen: lessen uit de migratie van mijn hele ecosysteem

Clément Sauvage14 min leestijd
Waarom ik Hygraph inruilde voor Sanity

Mijn blog, ⌘+F en de podcast ⌘+P draaien nu op Sanity in plaats van Hygraph. Wat de overstap in gang zette, wat ik Hygraph nog steeds nageef, waarin Sanity niet beter is en welke checklist ik nu gebruik om een CMS te kiezen.

Er zijn migraties die je blijft uitstellen omdat alles werkt. Mijn website draaide. De artikelen verschenen in meerdere talen, de podcast ⌘+P had zijn RSS-feeds en ⌘+F zijn eigen plek. Hygraph deed wat het moest doen.

En toch is het zover: clementsauvage.me, cmdf.io en de podcast ⌘+P draaien nu in productie op Sanity. Eén project, één contentmodel, zeven talen.

Dit artikel is geen verhaal van “Hygraph is slecht, Sanity is geweldig”. Hygraph heeft me goed geholpen en blijft voor bepaalde situaties een uitstekende keuze. Het is het verhaal van veranderende behoeften, met twee heel concrete aanleidingen — kosten en AI — en een bredere gedachte over hoe je als ondernemer in 2026 een SaaS-tool kiest én weer achter je laat.


Het vertrekpunt: een stack die werkte

Dit was mijn stack:

  • Hygraph als headless CMS met native GraphQL
  • Next.js 16 (App Router, Turbopack), Tailwind v4
  • Apollo Client voor de GraphQL-API
  • next-intl voor zeven talen
  • Clever Cloud Cellar (S3) achter Cloudflare voor een deel van de bestanden, Mux voor video

Niets exotisch. Een moderne, nette stack die ik een paar maanden geleden nog aan klanten aanraadde.

Het probleem was geen bug. Het was de ontwikkeling: meer talen, meer content, meer websites en een manier van werken die steeds meer op AI-agents leunt. Bij elke stap kostte Hygraph me iets meer — geld of frictie.

Mijn oude Hygraph-editor: de Franse en Engelse titels en ondertitels van ‘Het recept voor een geweldige iOS-app’ in één item.

Mijn oude Hygraph-editor: de Franse en Engelse titels en ondertitels van ‘Het recept voor een geweldige iOS-app’ in één item. Screenshot uit mijn project, oktober 2026.


Aanleiding 1: de kosten, vooral de kosten van talen

Zeven talen in een prijsmodel dat op twee of drie is afgestemd

Hier begon het. Ik publiceer op zijn minst in het Frans en Engels en mijn frontend ondersteunt zeven talen. Bij Hygraph is lokalisatie een betaalde functie met staffels:

  • Het gratis Hobby-plan bevat 2 talen.
  • Growth begint vanaf $199 per maand en bevat 3 talen.
  • Daarboven kom je uit bij opties en Enterprise, op offerte (tot 80 talen).

Voor een zelfstandige maker of klein bedrijf dat in meerdere talen vindbaar wil zijn, is dat een muur. Meertaligheid is geen luxe voor een multinational; het is dagelijkse praktijk voor Europese bedrijven. Dat je er een premiumoptie van maakt, voelt voor mij als een misser.

De talen van mijn Hygraph-project: Frans als standaard, Engels, en met die twee talen zit ik al aan de limiet van het plan.

De talen van mijn Hygraph-project: Frans als standaard, Engels, en met die twee talen zit ik al aan de limiet van het plan. Screenshot uit mijn project, oktober 2026.

De sprong naar Pro

De volgende stap was de overstap van gratis naar betaald. Hobby is op sommige punten royaal, maar biedt maar één omgeving. Zodra je een echte staging-omgeving nodig hebt om een schemaverandering te testen zonder productie stuk te maken, moet je naar het volgende plan. Voor iets basaals als een preproductieomgeving ineens van nul naar $199 per maand gaan, klopt voor een persoonlijke website en twee communityprojecten niet qua prijs-kwaliteit.

API-quota en assetverkeer

Een derde, minder zichtbare bron van frictie: de quota.

  • 500.000 API-bewerkingen per maand bij Hobby, 1 miljoen bij Growth. Dat klinkt als veel, totdat je talen, gegenereerde pagina’s, regelmatig opnieuw gemaakte podcastfeeds en preview-builds bij elkaar optelt.
  • 100 GB assetverkeer bij Hobby. Podcastcovers, artikelbeelden en visuals voor ⌘+F tellen op.

Los van elkaar is geen van deze limieten absurd. Maar samen, met drie websites waarvoor ik eigenlijk drie aparte Hygraph-projecten nodig had, leveren ze een rekening op die sneller groeit dan het publiek.

Wat Sanity hierin verandert

Bij Sanity ziet de rekensom er anders uit:

  • Prijs — Hygraph Hobby: $0; Sanity Free: $0.
  • Talen — Hygraph Hobby: 2; Sanity Free: onbeperkt*.
  • Gebruikers — Hygraph Hobby: 3; Sanity Free: 20.
  • Omgevingen / datasets — Hygraph Hobby: 1; Sanity Free: 2 (productie + staging).
  • API-verzoeken — Hygraph Hobby: 500.000 bewerkingen per maand; Sanity Free: 1 miljoen CDN-verzoeken + 250.000 API-verzoeken per maand.
  • Assets — Hygraph Hobby: 100 GB verkeer; Sanity Free: 100 GB opslag + 100 GB bandbreedte.

* Sanity telt geen talen, maar ‘unieke attributen’ per dataset (2.000 in Free, 10.000 in Growth). Bij lokalisatie op veldniveau vermenigvuldigt elke taal de attribuutpaden. Dat is de limiet om in de gaten te houden; daarover later meer.

De prijzen zijn eind september 2026 gecontroleerd op de officiële pagina’s van Hygraph en Sanity. Ze veranderen regelmatig, dus controleer ze voordat je een keuze maakt.

En als Free niet meer voldoet, kost Sanity Growth $15 per gebruiker per maand. Voor een team van twee of drie is dat nog lang geen $199 instapprijs bij Hygraph Growth — met alle talen erbij.


Aanleiding 2: AI, of een CMS als gereedschap voor agents

De kosten maakten dat ik verder ging kijken. AI liet me voor Sanity kiezen.

Mijn manier van schrijven is veranderd. Ik schrijf, vertaal, redigeer en publiceer steeds vaker met agents — Claude, Codex — die aan mijn code en content werken. De vraag is niet langer “ziet de editor er mooi uit?”, maar: kan mijn agent mijn content net zo goed begrijpen en bewerken als ik?

Op dat vlak heeft Sanity een voorsprong.

De MCP-server: vanuit Claude of Codex in je CMS schrijven

Sanity heeft een officiële MCP-server op https://mcp.sanity.io. Eén commando is genoeg om hem aan te sluiten:

npx sanity@latest mcp configure

De opdracht herkent de editor (Claude Code, Cursor, VS Code) en configureert de verbinding met de inloggegevens van de CLI. Voor Claude Code kun je de server ook handmatig toevoegen:

claude mcp add Sanity -t http https://mcp.sanity.io --scope user

Daarna kan de agent content opvragen met GROQ en het schema lezen, documenten aanmaken, aanpassen, publiceren en intrekken, releases beheren, assets via een URL uploaden en het schema deployen.

In de praktijk ziet mijn werkwijze er nu zo uit: ik werk met de agent aan een artikel, lees het na en laat de agent meteen een concept in Sanity maken met de juiste velden, tags en vertalingen. Ik controleer het in Studio en publiceer het. Geen kopieer-en-plakwerk meer tussen een Markdown-editor en een webinterface.

Vertalen naar zeven talen

Met zeven talen is vertalen geen detail, maar de helft van het redactionele werk. Met MCP en de ingebouwde AI-functies van Sanity (AI Assist, Agent Actions) kan ik voor elke taal een eerste versie maken en die vervolgens laten nalezen. AI doet het zware werk; de mens heeft het laatste woord, zeker over toon en technische termen.

Mijn Sanity Studio: de artikelenlijst van clementsauvage.me en de Franse en Engelse titels in één document.

Mijn Sanity Studio: de artikelenlijst van clementsauvage.me en de Franse en Engelse titels in één document. Screenshot uit mijn project, oktober 2026.

Schema’s die AI kan lezen

Dit is het meest onderschatte argument. Bij Sanity is het contentmodel TypeScript-code die in de repository is geversioneerd. Als een agent mijn project opent, ziet hij tegelijk de Next.js-frontend, de queries en de precieze definitie van elk documenttype. Hij hoeft het model niet eerst in een webinterface te ‘ontdekken’: hij leest het net als de rest van de code.

Voor iemand die graag no-code-interfaces gebruikt, is dat een nadeel (daar kom ik op terug). Voor een agent is het een doorslaggevend voordeel: alle context staat op dezelfde plek.


Wat er technisch veranderde door de migratie

Lokalisatie op veldniveau

Ik koos voor lokalisatie op veldniveau: één document per artikel, met velden waarin per taal een waarde staat. De officiële plugin sanity-plugin-internationalized-array doet het werk.

De configuratie gebruikt de talenlijst uit i18n/locales, dezelfde bron als next-intl, en maakt de typen string en text lokaliseerbaar. In het schema krijgen title en excerpt de typen internationalizedArrayString en internationalizedArrayText. De slug wordt afgeleid van de Franse titel; publicatiedatum en omslagafbeelding blijven gedeeld. De taalcodes verschijnen in hoofdletters.

// sanity.config.ts
import { defineConfig } from 'sanity'
import { internationalizedArray } from 'sanity-plugin-internationalized-array'
import { LOCALES } from './i18n/locales'

export default defineConfig({
  plugins: [
    internationalizedArray({
      languages: LOCALES.map((id) => ({ id, title: id.toUpperCase() })),
      fieldTypes: ['string', 'text'],
    }),
  ],
})

// schemas/post.ts
import { defineType, defineField } from 'sanity'

export const post = defineType({
  name: 'post',
  title: 'Artikel',
  type: 'document',
  fields: [
    defineField({ name: 'title', type: 'internationalizedArrayString' }),
    defineField({ name: 'excerpt', type: 'internationalizedArrayText' }),
    defineField({
      name: 'slug',
      type: 'slug',
      options: { source: (doc: any) => doc.title?.find((t: any) => t.language === 'fr')?.value },
    }),
    defineField({ name: 'publishedAt', type: 'datetime' }),
    defineField({ name: 'cover', type: 'image', options: { hotspot: true } }),
  ],
})

Waarom de velden lokaliseren in plaats van een document per taal maken? Mijn artikelen delen het meeste — datum, beelden, tags, auteurs — en alleen de teksten veranderen. Eén document betekent één bron van waarheid, en een agent hoeft voor een vertaling maar één object aan te passen.

Een detail dat je een avond kan kosten: sinds versie 5 van de plugin wordt de taal opgeslagen in het veld language, niet meer in _key. Oude voorbeelden op internet met _key == "fr" werken dus niet meer.

Van Apollo en GraphQL naar GROQ

Dit was de grootste klus aan de frontend. Ik stapte over van Apollo Client naar next-sanity, GROQ en TypeGen.

Voorheen haalde Apollo met een GraphQL-query de tien nieuwste posts op: posts(locales: [$locale, fr], orderBy: publishedAt_DESC, first: 10), met titel, slug, excerpt en de URL van de omslagafbeelding. Vervolgens gaf client.query de locale als variabele mee.

Nu zoekt next-sanity met GROQ naar documenten van het type post met een slug.current, gesorteerd op publishedAt van nieuw naar oud en beperkt tot tien resultaten. De projectie gebruikt coalesce voor titel en excerpt: eerst de gevraagde taal, daarna Frans als fallback. slug.current en cover.asset->url worden direct teruggegeven. De aanroep is client.fetch(POSTS_QUERY, { locale }).

// Voorheen: Apollo + Hygraph GraphQL
const GET_POSTS = gql`
  query Posts($locale: Locale!) {
    posts(locales: [$locale, fr], orderBy: publishedAt_DESC, first: 10) {
      title
      slug
      excerpt
      coverImage { url }
    }
  }
`
const { data } = await client.query({ query: GET_POSTS, variables: { locale } })

// Nu: next-sanity + GROQ
import { defineQuery } from 'next-sanity'

export const POSTS_QUERY = defineQuery(`
  *[_type == "post" && defined(slug.current)] | order(publishedAt desc)[0...10]{
    "title": coalesce(title[language == $locale][0].value, title[language == "fr"][0].value),
    "excerpt": coalesce(excerpt[language == $locale][0].value, excerpt[language == "fr"][0].value),
    "slug": slug.current,
    "cover": cover.asset->url
  }
`)

const posts = await client.fetch(POSTS_QUERY, { locale })

Daarna:

npx sanity typegen generate

TypeGen genereert TypeScript-types uit het schema en de queries. Het resultaat van de query is volledig getypeerd zonder dat ik zelf ook maar één interface hoef te schrijven.

Wat ik ervoor terugkreeg: minder afhankelijkheden (geen Apollo meer en geen clientcache om te configureren), een taal-fallback direct in de query met coalesce en projecties die precies de vorm teruggeven die de component nodig heeft.


Wat ik Hygraph nageef

Het zou niet eerlijk zijn om het hierbij te laten. Hygraph heeft echte sterke punten, en sommige daarvan mis ik.

  • GraphQL als basis. Een standaard die het hele team kent, met volwassen tooling. Je zit niet vast aan een eigen querytaal.
  • Native lokalisatie. Bij Hygraph zijn talen een eersteklasfunctie: je vinkt een taal aan en elk veld kan worden gelokaliseerd. Geen plugin en geen configuratie. Eenvoudiger — alleen duur.
  • Een no-code-schemabouwer. Iemand zonder technische achtergrond kan het contentmodel zelfstandig via de interface aanpassen. Bij Sanity kan dat niet zonder code.
  • Content Federation. Externe API’s koppelen en alles via één GraphQL-endpoint aanbieden is krachtig voor bedrijven met verspreide gegevensbronnen. Ik had het niet nodig, maar het is een echt onderscheidend vermogen.

Het Blog Post-model van mijn Hygraph-project: gelokaliseerde velden en de beschikbare veldtypen in de schemabouwer.

Het Blog Post-model van mijn Hygraph-project: gelokaliseerde velden en de beschikbare veldtypen in de schemabouwer. Screenshot uit mijn project, oktober 2026.

Werk je in een middelgroot marketingteam, met weinig talen, niet-technische redacteuren die zelfstandig het model willen aanpassen en een budget voor het CMS, dan blijft Hygraph een prima keuze.

Mijn bezwaar gaat over één specifiek punt: het prijsmodel benadeelt kleine meertalige bedrijven. Dat is een legitieme commerciële keuze, maar daardoor val ik buiten de doelgroep.


Wat Sanity niet beter doet

Dezelfde eerlijkheid geldt de andere kant op.

GROQ moet je leren. Het is een eigen taal. Eenmaal onder de knie is die krachtig, beknopt en prettig, maar mijn queries zijn er wel aan een CMS gebonden. Ik heb een prijsafhankelijkheid ingeruild voor een syntaxisafhankelijkheid, bewust. (Sanity heeft ook een GraphQL-API, maar dan verlies je een groot deel van het voordeel.)

Alles loopt via de developer. Een schema als code is geweldig voor developers en agents. Voor een niet-technische redacteur die een veld wil toevoegen, blijft de deur dicht. In mijn geval ben ik zelf de developer, dus speelt dat niet. In een team kan het wel degelijk een punt zijn.

Internationalisering is minder native. Je moet een strategie kiezen (veld of document), een plugin installeren, versiemigraties beheren (de bekende stap van _key naar language) en de limiet voor unieke datasetattributen in de gaten houden. Met zeven talen en lokalisatie op veldniveau kun je die snel bereiken. Niets onoverkomelijks, maar Hygraph neemt dat werk uit handen.


Verder dan het CMS: in 2026 een SaaS kiezen — en weer verlaten

Deze migratie herinnerde me vooral aan één ding: een tool is geen definitieve keuze, maar een keuze voor een bepaald moment. Hygraph was de juiste keuze toen ik mijn stack opzette. Toen mijn behoeften veranderden, was dat niet meer zo.

Drie lessen die ik meeneem en met klanten deel:

1. Bereken de kosten over je groeipad, niet alleen voor vandaag. Prijsmodellen zijn zo opgezet dat de start moeiteloos voelt. Vraag jezelf af: wat kost het met twee keer zoveel talen, content, websites of bijdragers? Daar komen de verschillen aan het licht.

2. In 2026 is “kan een agent ermee werken?” een belangrijk criterium. Een tool met een officiële MCP-server, een model dat als code leesbaar is en een scriptbare API bespaart je elke week uren. Een tool die alleen met de muis te bedienen is, wordt een flessenhals.

3. Houd je content overdraagbaar. Ik kon migreren omdat mijn content gestructureerd was en ik de frontend beheerde. Als je van tool wisselt, bepaalt de kwaliteit van je contentmodel of de migratie een week of drie maanden duurt.


Checklist: een headless CMS kiezen

Dit zijn de vragen die ik mezelf nu stel, voor mijn eigen projecten en voor klanten.

Content en talen

  • ☐ Hoeveel talen heb je nu nodig? En over twee jaar?
  • ☐ Is lokalisatie inbegrepen, beperkt of betaal je per taal?
  • ☐ Lokaliseer je op veldniveau, documentniveau of allebei?

Kosten

  • ☐ Wat kost de volgende planstap, en wat triggert die (gebruikers, talen, omgevingen, quota)?
  • ☐ Hoe worden API-aanroepen geteld en wat gebeurt er als je de limiet overschrijdt?
  • ☐ Zit een stagingomgeving al in het gratis plan?

Team

  • ☐ Wie past het contentmodel aan: een developer of een redacteur?
  • ☐ Heb je realtime samenwerking nodig?

Ontwikkeling

  • ☐ Staat het schema als versiebeheerbare code naast de frontend?
  • ☐ Een standaardquerytaal (GraphQL) of een eigen taal (GROQ...): wil je die leren?
  • ☐ Worden types automatisch gegenereerd?

AI en agents

  • ☐ Is er een officiële MCP-server?
  • ☐ Kan een agent het schema lezen en content maken, aanpassen en publiceren?
  • ☐ Zijn er ingebouwde vertaal- of generatietools, en wat kosten ze?

Vertrek

  • ☐ Kun je alle content exporteren naar een open formaat?
  • ☐ Wat zou een migratie over twee jaar kosten?

Beantwoord je deze vragen vooraf, dan voorkom je de meeste verrassingen. Beantwoord je ze achteraf, zoals ik, dan weet je in elk geval wanneer het tijd is om te vertrekken.


En nu?

Mijn hele ecosysteem staat nu in één Sanity-project: de artikelen van deze blog, de content van ⌘+F en de afleveringen van ⌘+P. Eén model, zeven talen en agents die rechtstreeks in het CMS werken.

Tegenwoordig raad ik Sanity ook klanten aan. Drie van hen zijn al overgestapt. De migratie van hun contentmodellen en duizenden pagina’s duurde maar een paar uur — bij de grootste projecten ongeveer tien uur. Sommigen hebben hun migratie in drie maanden terugverdiend.

Twijfel je over je contentstack, overweeg je een migratie of wil je AI-agents aan je CMS koppelen? Dat zijn precies de onderwerpen waarbij ik klanten begeleid met BNC Consulting. Stuur me een bericht.

En wil je dit met andere developers bespreken, sluit je dan aan bij de ⌘+F-community. Zulke ervaringen delen we ook tijdens meetups, met een kop koffie of aan tafel.

— Clément

Blog

Gerelateerde berichten