
Sanity CMS-guide: Slik publiserer vi på 10 språk
Vi har publisert over 400 innholdsartikler på tvers av 4 nettsteder og 10 språk gjennom Sanity CMS. Her er det vi har lært -- fra schemadesign til automatisert flerspråklig publisering.
Sanity CMS er en headless innholdsplattform bygget rundt strukturert innhold, en sanntids Content Lake og en tilpassbar React-basert editor kalt Sanity Studio. Den bruker GROQ for spørringer, Portable Text for rikt innhold og schema-as-code for innholdsmodellering. Denne guiden dekker oppsett, schemadesign, GROQ, Portable Text, flerspråklig arkitektur og prissetting.
Hva er Sanity CMS?
Sanity er en strukturert innholdsplattform -- det teamet hos Sanity.io kaller et "content operating system." I motsetning til tradisjonelle CMS-er som lagrer HTML-blobs i en database, lagrer Sanity alt innhold som strukturert JSON i et administrert backend kalt Content Lake. Du spør mot det med GROQ eller GraphQL og gjengir innholdet i et hvilket som helst frontend: Next.js, React Native, Svelte, en mobilapp, et CLI-verktøy -- hva som helst.
Selskapene som bruker det spenner over hele skalaen. Nike, Figma, Puma og Cloudflare kjører Sanity i enterprise-skala. Startups bruker det fordi gratisplanen er genuint brukbar (mer om prising senere). Vi bruker det fordi ingenting annet ga oss fleksibiliteten til å bygge en fullt automatisert publiseringspipeline for 10 språk.
Content Lake-arkitektur
Content Lake er Sanity sitt administrerte backend. Tenk på det som et hostet dokumentlager som synkroniserer i sanntid på tvers av alle tilkoblede klienter. Når en redaktør endrer et avsnitt i Sanity Studio, ser en annen redaktør det øyeblikkelig -- ingen lagre-knapp, ingen merge-konflikter, ingen databasemigreringer.
Under panseret lagres dokumenter som strukturert JSON med typede felter. Alle mutasjoner spores gjennom en transaksjonslogg, så du får full versjonshistorikk som standard. Sanntidssynkroniseringen bruker en lytterbasert arkitektur (beskrevet i Sanity sin GitHub-arkitekturdokumentasjon) som sender endringer til alle abonnenter via RxJS-observables.
Hva skiller dette fra, for eksempel, en PostgreSQL-database med et REST API? Content Lake håndterer innholdsmodellering, tilgangskontroll, CDN-caching, bildetransformasjoner og sanntidssamarbeid som én administrert tjeneste. Du kjører ikke migreringer. Du administrerer ikke replikaer. Du definerer bare schemaer og spør mot innhold.
Sanity Studio: din tilpassbare editor
Sanity Studio er en åpen kildekode React-applikasjon som fungerer som redigeringsgrensesnittet ditt. Det er ikke et hostet adminpanel -- det er en React-app som lever i kodebasen din. Du kan tilpasse alle aspekter av det: tilpassede inndatakomponenter, betingede felter, dokumenthandlinger, strukturbyggermønstre og plugins.
Sanntidssamarbeid er innebygd. Flere redaktører kan jobbe med samme dokument samtidig med tilstedeværelsesindikatorer og direkteoppdateringer. Hvis du har brukt Google Docs, er opplevelsen lignende -- du ser andres pekere og endringer i sanntid.
Vi distribuerer Studio vår med npx sanity deploy, som hoster den på Sanity sitt CDN på et tilpasset underdomene. Du kan også selvhoste den siden det bare er en React-app. Vi rangerte Sanity høyt i vår sammenligning av headless CMS-er hovedsakelig på grunn av Studio sin fleksibilitet.
Slik setter du opp et Sanity-prosjekt
For å sette opp Sanity CMS installer du CLI med npm create sanity@latest, velger en prosjektmal, konfigurerer schemafiler og kjører npx sanity dev for å starte Studio lokalt. Hele prosessen tar under 5 minutter.
Forutsetninger og installasjon
Du trenger Node.js 18+ og npm (eller pnpm). Det er alt. Kjør init-kommandoen:
npm create sanity@latest
# Du vil bli bedt om:
# - Innloggingsmetode (Google, GitHub, e-post)
# - Prosjektnavn
# - Datasett-navn (standard: "production")
# - Prosjektmal (blogg, netthandel, tom)
# - TypeScript? (anbefalt: ja)CLI-verktøyet stiller opp et prosjekt med alt du trenger. Her er hvordan prosjektstrukturen ser ut:
Prosjektstruktur forklart
my-sanity-project/
├── schemas/ # Innholdsschemaene dine (her bruker du mest tid)
│ ├── index.ts # Schema-register -- importerer og eksporterer alle typer
│ ├── post.ts # Dokumenttypedefinisjoner
│ └── blockContent.ts # Rikt tekst / Portable Text-konfig
├── sanity.config.ts # Hovedkonfig -- plugins, Studio-struktur, datasett
├── sanity.cli.ts # CLI-konfig -- prosjekt-ID, datasett
├── package.json
└── tsconfig.jsonsanity.config.ts-filen er inngangspunktet ditt. Her er et minimalt eksempel:
// 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 },
})visionTool()-pluginen gir deg en GROQ-lekeplass inne i Studio -- du vil bruke den konstant under utvikling.
Distribuere Studio
Start lokalt med npx sanity dev (kjører på localhost:3333). Når du er klar til å dele med redaktører, distribuerer du til Sanity sitt CDN:
npx sanity deploy
# Ber om et vertsnavn, f.eks. "my-blog"
# Distribuerer til https://my-blog.sanity.studioProffips: kjør npx sanity@latest schema deploy etter enhver schemaendring. Dette laster opp schemaet ditt til Sanity sitt API, noe som aktiverer funksjoner som GraphQL API og schemabevisst verktøy (inkludert MCP-serveren vi dekker senere).
Schemadesign i Sanity CMS
Sanity-schemaer er definert som JavaScript- eller TypeScript-objekter i kodebasen din. Hvert schema spesifiserer en dokumenttype med felter, valideringsregler og tilpassede inndatakomponenter. Endringer i schemaer er øyeblikkelige -- ingen databasemigreringer kreves. Dette er "schema-as-code"-tilnærmingen, og det er grunnen til at vi valgte Sanity over Contentful.
Felttyper og validering
Sanity leveres med et rikt sett av felttyper. Her er de vi bruker mest:
| Felttype | Brukstilfelle | Eksempel |
|---|---|---|
string | Kort tekst, titler, slugs | Innleggstittel, forfatternavn |
text | Flerlinje ren tekst | Utdrag, beskrivelser |
number | Heltall, desimaltall | Lesetid, sorteringsrekkefølge |
boolean | Veksleknapper | Fremhevet-flagg, utkast-status |
array | Lister, rik tekst (Portable Text) | Innholdstekst, tagger |
reference | Koblinger til andre dokumenter | Forfatter, kategori |
image | Bilder med metadata | Forsidebilde med alt-tekst |
slug | URL-vennlige strenger | Autogenerert fra tittel |
object | Nestede feltgrupper | SEO-felter (metaTitle + metaDescription) |
date / datetime | Datoer | Publiseringsdato |
Hvert felt støtter validering via en validation-tilbakeringing. Du kan håndheve påkrevde felter, min/maks-verdier, regex-mønstre og tilpassede regler:
defineField({
name: 'seoDescription',
title: 'Meta Description',
type: 'string',
validation: (Rule) =>
Rule.required()
.min(145)
.max(160)
.warning('Meta description should be 145-160 characters'),
})Tilpassede blokktyper (våre produksjonseksempler)
Her blir Sanity interessant -- og her viser ingen av de 6 konkurrerende guidene noen kode. I produksjonsskjemaet vårt definerer vi fem tilpassede blokktyper inne i body-arrayen: block (standardtekst), table, codeBlock, chartBlock og inlineImage.
Her er vår codeBlock-definisjon:
// 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',
},
],
})Og her er hvordan body-feltet refererer til alle våre tilpassede typer samlet:
// schemas/fields/body.ts
defineField({
name: 'body',
title: 'Body',
type: 'array',
of: [
{ type: 'block' }, // Standard Portable Text (avsnitt, overskrifter, lister)
{ type: 'table' }, // @sanity/table-pluginen
{ type: 'codeBlock' }, // Vår tilpassede kodeblokk
{ type: 'chartBlock' }, // Datavisualisering (stolpe, linje, kake)
{ type: 'inlineImage' }, // Bilder med alt-tekst og bildetekster
],
})Dette gir redaktørene våre et rikt innholdsverktøysett samtidig som hvert element forblir typet og søkbart. En chartBlock er ikke bare et ugjennomsiktig HTML-innbygg -- det er strukturerte data med feltene chartType, title, dataPoints og dataLabels. Det betyr noe når du prøver å gjengi det samme innholdet på tvers av nett, e-post og mobil.
Beste praksis for schemaorganisering
Hold schemaer modulære. Vi deler våre på tvers av filer etter type: schemas/documents/post.ts, schemas/objects/codeBlock.ts, schemas/objects/chartBlock.ts. Importer dem alle i 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]Den viktigste innsikten vi fikk fra å jobbe med strukturert innhold: schemaet ditt ER innholdsmodellen din. Hvis du tenker på det som context engineering for innholdsteamet ditt, tar du bedre designbeslutninger. Hvert felt du legger til bør tjene et formål -- enten for redaktører, for gjengivelse eller for spørringer.
GROQ: Sanity sitt spørringsspråk
GROQ (Graph-Relational Object Queries) er Sanity sitt åpen kildekode-spørringsspråk for filtrering, sammenføyning og projeksjon av JSON-dokumenter. Den grunnleggende syntaksen er *[filter]{projection} -- velg alle dokumenter som samsvarer med et filter, og form deretter utdataene. Det er mer konsist enn GraphQL for Sanity-spesifikke spørringer og, etter vår erfaring, raskere å lære.
Grunnleggende spørringer: filter og projeksjon
Den enkleste spørringen henter alle dokumenter av en type:
// Hent alle innlegg -- bare tittel og slug
*[_type == "post"]{
title,
"slug": slug.current
}
// Filtrer etter språk, utvid forfatterreferanse
*[_type == "post" && language == "en"]{
title,
"slug": slug.current,
"authorName": author->name,
"authorImage": author->image,
"categoryTitle": category->title,
publishedAt
}->-operatoren følger referanser. author->name betyr "følg forfatterreferansen og returner navnefeltet." Ingen separate spørringer, ingen N+1-problemer, ingen JOINs -- det er ett uttrykk.
Sammenføyninger, sortering og paginering
For bloggindekssidene våre trenger vi sorterte, paginerte innlegg med utvidede referanser:
// Paginerte innlegg med full 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] gir deg de første 10 resultatene (0-indeksert, eksklusiv slutt). | order(publishedAt desc) sorterer nyeste først. Projeksjonen former utdataene til å inkludere nøyaktig det frontenden din trenger -- ikke noe mer.
Du kan teste alle disse spørringene interaktivt ved hjelp av Vision-pluginen inne i Sanity Studio. Den er uvurderlig under utvikling. For flere mønstre, sjekk GROQ-juksearket.
GROQ vs GraphQL
Sanity støtter både GROQ og GraphQL. Når bør du bruke hva?
GROQ er Sanity sitt opprinnelige språk. Det håndterer sammenføyninger, projeksjoner og beregnede felter i én enkelt spørringsstreng. Det er hva Content Lake er optimalisert for.
GraphQL er tilgjengelig etter at du distribuerer schemaet ditt (npx sanity@latest schema deploy). Bruk det når du trenger standardisert verktøy -- for eksempel hvis frontenden din allerede bruker Apollo Client, eller hvis teamet ditt kan GraphQL men ikke GROQ.
Vi bruker GROQ utelukkende. Det er mer uttrykksfullt for Sanity-data, og Vision-pluginen gjør feilsøking av spørringer trivielt.
Portable Text: rikt innhold gjort riktig
Portable Text er Sanity sin spesifikasjon for strukturert rik tekst. I stedet for å lagre innhold som HTML-strenger, lagrer den en array av typede blokker -- avsnitt, overskrifter, bilder, kodeutdrag, tabeller -- hver som et JSON-objekt. Dette gjør innhold gjengitt i et hvilket som helst rammeverk, hvilken som helst plattform, i hvilket som helst format.
Datastrukturen
Her er hva et avsnitt og en kodeblokk ser ut som 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({ ... })"
}
]Hver blokk har en _type og _key. Standard tekstblokker bruker "block" med barn-spans (som støtter markeringer som fet, kursiv og lenker). Tilpassede blokker -- som vår codeBlock, chartBlock, table og inlineImage -- bruker sin egen _type og bærer strukturerte felter.
Hvorfor betyr dette noe? Fordi HTML er et gjengivelsesformat, ikke et lagringsformat. Hvis du lagrer <h2>Tittel</h2><p>Litt <strong>tekst</strong></p> i databasen din, har du låst deg inn i webgjengivelse. Du kan ikke rent trekke ut det for en mobilapp, et e-postnyhetsbrev, en PDF eller en AI-agents kontekstvindu. Portable Text skiller innhold fra presentasjon. Portable Text-spesifikasjonen er åpen kildekode -- det er ikke en Sanity-innlåsing.
Tilpassede blokker i produksjon
Vår pipeline konverterer Markdown til Portable Text ved hjelp av et Python-skript (scripts/md_to_portable_text.py). Konverteren håndterer standardblokker pluss våre fire tilpassede typer:
table-- bruker@sanity/table-pluginschemaet. Rader og celler lagret som strukturerte data.codeBlock-- språk og kode som separate felter, noe som muliggjør syntaksutheving ved gjengivelse.chartBlock-- diagramtype, tittel, akseetiketter, serienavn og datapunkter som strukturert JSON. Frontenden gjengir disse med Chart.js.inlineImage-- alt-tekst, kilde og valgfri bildetekst som separate felter.
Denne strukturen betyr at vi kan spørre etter alle kodeeksempler i bloggen vår (*[body[]._type == "codeBlock"]), finne innlegg med diagrammer, eller trekke ut alle bilder med manglende alt-tekst -- alt gjennom GROQ.
Gjengivelse av Portable Text
På frontenden bruker du @portabletext/react (eller Svelte/Vue-ekvivalentene). Du registrerer tilpassede komponenter for hver blokktype:
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>
),
},
}
// I komponenten din:
<PortableText value={post.body} components={components} />Det er hele gjengivelsespipelinen. PortableText-komponenten håndterer standardblokker (avsnitt, overskrifter, lister, markeringer) automatisk. Du definerer bare tilpassede komponenter for dine tilpassede typer.
Flerspråklig innhold med Sanity CMS
Sanity støtter flerspråklig innhold gjennom lokalisering på dokumentnivå (separate dokumenter per språk koblet av en kanonisk referanse) eller lokalisering på feltnivå (oversatte felter innenfor ett dokument). Dokumentnivå fungerer bedre for SEO og storskala publisering -- det er det vi bruker på tvers av vår 10-språkspipeline.
Lokalisering på dokumentnivå vs feltnivå
| Aspekt | Dokumentnivå | Feltnivå |
|---|---|---|
| Tilnærming | Separat dokument per språk | Alle oversettelser i ett dokument |
| SEO | Hvert dokument har sin egen URL/slug | Enkelt URL, vanskeligere å betjene per-språk-sider |
| Spørringskompleksitet | Enkle filtre: language == "de" | Nestet felttilgang: title.de |
| Innholdsstørrelse | Små, fokuserte dokumenter | Ett stort dokument med alle språk |
| Best for | Blogginnlegg, sider, SEO-drevet innhold | Små UI-strenger, etiketter, metadata |
| Vår vurdering | Vi bruker dette til alt | Bare for delte UI-strenger |
Vi valgte lokalisering på dokumentnivå fordi hver oversettelse får sin egen slug, sin egen URL og sin egen metadata. Den norske versjonen av et innlegg om Supabase vs Firebase får slugen supabase-vs-firebase-sammenligning -- ordentlig norsk, ikke et URL-parameterhack.
Vår 10-språks pipeline-arkitektur
Slik fungerer den automatiserte pipelinen vår: vi skriver et innlegg på engelsk, og oversetter det deretter til 9 ytterligere språk (tysk, fransk, nederlandsk, spansk, tyrkisk, italiensk, svensk, norsk, arabisk). Hver oversettelse går gjennom Markdown-konvertering, Portable Text-generering og Sanity API-publisering.
Arkitekturen ser slik ut:
- Skriv -- engelsk Markdown med YAML-frontmatter
- Oversett -- AI-oversettelse til 9 språk (verifisert for fullstendighet og diakritiske tegn)
- Konverter -- Python-skript konverterer hver
.md-fil til Portable Text JSON - Publiser -- API-kall til Sanity: opprett dokument, last opp bilder, patch referanser
Hvert dokument har et language-felt og en canonicalPost-referanse som peker til det engelske originalet. Her er GROQ-spørringen for å hente et innlegg og alle oversettelsene:
// Hent et innlegg og alle oversettelsene
*[_type == "post" && slug.current == "sanity-cms-guide" && language == "en"][0]{
title,
language,
"translations": *[
_type == "post" &&
canonicalPost._ref == ^._id
]{
title,
language,
"slug": slug.current
}
}Schema-siden er grei -- et language-felt med en enum over støttede språk:
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(),
})En ting vi lærte på den harde måten: publiser det engelske dokumentet først, og patch deretter canonicalPost-referanser på oversettelser ved å bruke det publiserte dokument-IDet -- ikke drafts.-prefikset. Sanity behandler utkast og publiserte dokumenter som separate enheter internt.
For mer informasjon om hvordan denne pipelinen kobler til Model Context Protocol, se neste avsnitt.
Sanity AI-funksjoner: MCP, Canvas og Agent Context
Sanity posisjonerer seg som innholdsdriftsystemet for AI-æraen. Viktige AI-funksjoner inkluderer en MCP-server for at AI-agenter kan lese og skrive innhold, Canvas for AI-assistert redigering inne i Studio, og Agent Context for produksjons-AI-agenter som kan spørre mot strukturert innhold med schemakunnskap.
MCP-serverintegrasjon
Sanity MCP-serveren lar AI-agenter -- Claude Code, Cursor, Windsurf og andre -- samhandle med Sanity-arbeidsområdet ditt programmatisk. Agenter kan lese schemaer, utføre GROQ-spørringer, opprette dokumenter og administrere innhold uten tilpassede API-wrappere.
Vi bruker Sanity MCP-serveren daglig i innholdspipelinen vår. AI-agentene våre spør mot schemaet for å forstå dokumentstruktur, henter eksisterende innlegg for å finne interne koblingsmuligheter og publiserer nye dokumenter. MCP-protokollen gir agenter schemakunnskap -- de vet hvilke felter som finnes, hvilke typer de forventer og hvilke valideringsregler som gjelder. Hvis du bygger AI-agenter for bedrifter arbeidsflyter, er dette et kraftig mønster.
Agent Context for produksjons-AI
Agent Context er en separat funksjon for produksjonskvalitets-AI-integrasjoner. I motsetning til MCP-serveren (som er designet for utviklerverktøy), gir Agent Context skrivebeskyttet, avgrenset tilgang for AI-agenter som trenger å spørre mot innholdet ditt ved kjøretid -- tenk chatbots, anbefalingssystemer eller innholdspersonaliseringssystemer.
Forskjellen betyr noe: MCP er for byggetid og redaksjonelle arbeidsflyter (schemabeviste utviklingsverktøy), mens Agent Context er for kjøretidstilgang til innhold med riktig autentisering og hastighetsbegrensning.
Sanity sitt strukturerte innhold gir det en reell fordel her. Et WordPress-nettsted lagrer innhold som HTML-blobs -- en AI-agent må parse HTML for å forstå innholdet. Sanity lagrer typede JSON-dokumenter med definerte schemaer. En agent kan spørre mot *[_type == "product" && category == "electronics"]{name, price, features} og få rene, strukturerte data tilbake. Ingen skraping, ingen parsing, ingen gjetting.
Slik bruker vi Sanity hos Techsy
Dette er ikke en hypotetisk seksjon. Vi kjører Sanity CMS på tvers av 4 produksjonsnettsteder og publiserer på 10 språk med en automatisert pipeline vi har bygget over det siste året. Her er arkitekturen.
Innholdspipeline-arkitekturen vår
Pipelinen går fra forskning til publisert innlegg på alle 10 språk:
- Forskning -- nøkkelordanalyse, identifisering av konkurrentgap, SERP-mønstre
- Brief -- strukturert skrivespec med seksjonsveiledning, ordtall, interne lenker
- Skriv -- produser engelsk Markdown med YAML-frontmatter
- Konverter -- Python-skript transformerer Markdown til Portable Text JSON med våre 5 tilpassede blokktyper
- Publiser -- API-kall til Sanity:
createOrReplace-dokument, last opp bilder til Sanity CDN, patch forfatter-/kategorireferanser - Oversett -- AI-oversettelse til 9 språk, verifisert for fullstendighet
- Publiser oversettelser -- samme konverter-/publiseringsprosess per språk, med
canonicalPost-referanse patchet til engelsk original
Det tilpassede schemaet støtter typene block, table, codeBlock, chartBlock og inlineImage -- alle definert som produksjons-Sanity-schemaobjekter med valideringsregler. Blant AI-verktøy for startups vi har testet, har denne Sanity-baserte pipelinen vært den mest pålitelige for strukturert innhold i stor skala.
Erfaringer fra 400+ publiserte artikler
Noen ting vi skulle ønske noen hadde fortalt oss:
Rekkefølgen for referansepatch betyr noe. Sanity-referanser kan ikke peke til dokumenter som ikke eksisterer ennå. Publiser det engelske innlegget først, og opprett deretter oversettelser med canonicalPost som peker til det engelske dokumentets publiserte ID. Vi brøt dette flere ganger tidlig i prosessen.
Schemadistribusjon er per arbeidsområde. Hvis du kjører flere Sanity-prosjekter (vi kjører 4), må du distribuere schemaer til hvert enkelt separat: npx sanity@latest schema deploy per prosjektkonfig.
Gratisplanen er ekte. Vi kjørte to av de fire nettstedene våre på gratisplanen i måneder. 20 brukere, 500K API-forespørsler/måned, 100K CDN-forespørsler -- det er nok for et reelt produksjonsettsted, ikke bare et lekeprosjekt.
Portable Text-konvertering er flaskehalsen. Markdown til Portable Text er ikke trivielt. Nestede lister, tabeller inne i blokksitatene, kodeblokker med spesielle tegn -- kantsaker overalt. Vi har iterert på konverteringsskriptet i måneder.
Trenger du hjelp med å sette opp Sanity for prosjektet ditt? Vi har bygget flerspråklige innholdspipelines for 4 produksjonsnettsteder. Få en gratis konsultasjon
Prisgjennomgang for Sanity CMS
Sanity tilbyr tre planer: Gratis (20 brukere, 500K API-forespørsler/måned), Growth ($15/bruker/måned med avanserte roller og planlagte utkast) og Enterprise (tilpasset prising med SLA og compliance-funksjoner). Gratisplanen er den mest sjenerøse på markedet for headless CMS.
| Funksjon | Gratis | Growth ($15/bruker/mnd) | Enterprise |
|---|---|---|---|
| Brukere | 20 | 50 | Ubegrenset |
| API-forespørsler | 500K/måned | 2,5M/måned | Tilpasset |
| CDN-forespørsler | 100K/måned | 500K/måned | Tilpasset |
| Roller | Kun admin | Admin, Utvikler, Redaktør, Bidragsyter | Tilpassede roller |
| Samarbeid | Sanntidsredigering | + Planlagt publisering, utkast | + Arbeidsflyter |
| Support | Fellesskap | E-post | Dedikert + SLA |
| Compliance | -- | -- | SOC 2, HIPAA |
På gratisplanen kjører vi to av nettstedene våre uten å nå grensene. Growth-planen til $15/bruker/måned la til rollebasert tilgang (viktig når vi fikk ikke-tekniske redaktører) og planlagt publisering. Seere er gratis på Growth, noe som er en fin detalj -- du blir ikke straffet for å gi interessenter lesetilgang.
Hvordan sammenlignes dette med konkurrenter?
| Funksjon | Sanity Gratis | Contentful Gratis | Strapi Cloud Gratis | Payload Cloud |
|---|---|---|---|---|
| Brukere | 20 | 1 | 1 | 1 |
| Innholdstyper | Ubegrenset | 48 | Ubegrenset | Ubegrenset |
| API-kall | 500K/mnd | Inkludert | Inkludert | Inkludert |
| Tilpassede typer | Ja | Begrenset | Ja | Ja |
| Pris for å vokse | $15/bruker/mnd | $300/mnd | $29/mnd | $50/mnd |
Sanity sin 20-bruker gratisplan er eksepsjonell. Contentful begrenser deg til 1 bruker på gratis og hopper til $300/måned for Team-planen. Hvis du er en startup eller et lite team, lar Sanity sin gratisplan deg kjøre reelle produksjonsbelastninger uten å bruke noe.
Sanity tilbyr også et startupprogram som gir kvalifiserte startups ett år med gratis Growth-tilgang. Verdt å søke på hvis du kvalifiserer.
Ofte stilte spørsmål
Hva er Sanity CMS og hvordan fungerer det?
Sanity CMS er en headless innholdsplattform som lagrer strukturerte JSON-dokumenter i et administrert backend kalt Content Lake. Du redigerer innhold gjennom Sanity Studio (en tilpassbar React-app), spør mot det med GROQ eller GraphQL og gjengir det i et hvilket som helst frontend-rammeverk. Innhold synkroniserer i sanntid på tvers av alle tilkoblede klienter.
Er Sanity CMS gratis?
Ja. Sanity sin gratisplan inkluderer 20 brukere, 500K API-forespørsler per måned og 100K CDN-forespørsler -- den mest sjenerøse gratisplanen blant headless CMS-plattformer. Growth-planen koster $15 per bruker per måned og legger til rollebasert tilgang, planlagt publisering og høyere grenser. Enterprise-prising er tilpasset.
Hva er forskjellen mellom Sanity og Contentful?
Sanity bruker schema-as-code (schemaer lever i kodebasen din), GROQ for spørringer og et fullt tilpassbart åpen kildekode Studio. Contentful bruker GUI-basert innholdsmodellering, GraphQL og en hostet editor med mindre tilpasning. Sanity sin gratisplan inkluderer 20 brukere mot Contentful sine 1. Contentful har et større plugin-markedsplass.
Er Sanity CMS bra for nybegynnere?
Sanity Studio er intuitivt for innholdsredaktører -- redigeringsopplevelsen krever ingen teknisk kunnskap. Men å sette opp schemaer krever kompetanse i JavaScript eller TypeScript. Sanity gir utmerket dokumentasjon, prosjektmaler og en fellesskaps-Slack med aktiv support. Start med npm create sanity@latest og en bloggmal.
Kan jeg selvhoste Sanity?
Sanity Studio kan selvhostes fullt ut fordi det er en åpen kildekode React-applikasjon. Du kan distribuere den til Vercel, Netlify eller en hvilken som helst statisk hosting-leverandør. Content Lake-backenden er en administrert tjeneste -- det er ingen selvhostingsalternativ for datalaget. Dette er et kompromiss: du får null infrastrukturadministrasjon men ingen on-premises datakontroll.
Hvilken type database bruker Sanity?
Sanity sin Content Lake er ikke en tradisjonell SQL- eller NoSQL-database. Det er et administrert dokumentlager som lagrer innhold som strukturert JSON med et GROQ-spørringslag på toppen. Du samhandler ikke med den underliggende databasen direkte -- du samhandler gjennom Sanity sine APIer. Dokumenter har full versjonshistorikk og sanntidssynkronisering innebygd.
Er Sanity CMS åpen kildekode?
Sanity Studio er åpen kildekode under MIT-lisensen -- du kan forke det, tilpasse det og selvhoste det. Content Lake-backenden er proprietær SaaS. GROQ-spørringsspråkspesifikasjonen er også åpen kildekode, publisert på GitHub. Portable Text-spesifikasjonen er åpen kildekode også, vedlikeholdt på portabletext.org.
Hva er Portable Text i Sanity?
Portable Text er Sanity sin spesifikasjon for strukturert rik tekst. I stedet for å lagre innhold som HTML-strenger, representerer den avsnitt, overskrifter, bilder og tilpassede blokker som typede JSON-objekter i en array. Dette gjør innhold portabelt på tvers av rammeverk og plattformer. Du kan definere tilpassede blokktyper som kodeutdrag, diagrammer og tabeller med sine egne strukturerte felter.
Hva er GROQ og hvordan er det forskjellig fra GraphQL?
GROQ (Graph-Relational Object Queries) er Sanity sitt opprinnelige spørringsspråk. Syntaksen -- *[filter]{projection} -- er mer konsis enn GraphQL for Sanity-data, med innebygd støtte for sammenføyninger via -> -operatoren og beregnede felter. GraphQL er også tilgjengelig for team som foretrekker standardisert verktøy eller allerede bruker Apollo Client.
Hvordan håndterer Sanity flerspråklig innhold?
Sanity støtter lokalisering på dokumentnivå (separate dokumenter per språk koblet av kanoniske referanser) og lokalisering på feltnivå (oversatte felter innenfor ett dokument). Dokumentnivå er bedre for SEO fordi hver oversettelse får sin egen URL og metadata. Vi bruker lokalisering på dokumentnivå for å publisere på tvers av 10 språk med automatiserte oversettings- og publiseringspipelines.