Sanity.io Headless CMS Tutorial 2026: No es un CMS. Es una Base de Datos de Contenido en Tiempo Real
Tutorial Sanity.io 2026: aprende el patrón de 5 pasos para modelar contenido con schema-as-code, GROQ y Portable Text. No es un CMS — es infraestructura.
Sanity.io se llama "headless CMS" — pero esa etiqueta esconde el producto real: una base de datos de contenido en tiempo real que resulta que trae un admin React open-source
Si tratas Sanity como si fuera WordPress o Contentful — defines unos campos, llamas a la API, despliegas — tu modelo de contenido no va a sobrevivir al primer contacto con un flujo editorial real.
*El problema no es el editor ni la velocidad de la API. El problema es la disciplina del modelo de contenido. *
Aquí no hay un `ALTER TABLE` de SQL. La evolución del esquema es un problema de code-review y parches. Y GROQ sustituye los resolvers de GraphQL que asumías que necesitabas.
Los equipos que fracasan con Sanity son los que lo tratan como un CMS. Los que triunfan lo tratan como infraestructura.
La analogía más útil que he encontrado es pensar en Sanity como si fuera una base de datos Postgres especializada: no le pides permiso a la base de datos, le defines un esquema, le inyectas datos y la consultas. La diferencia es que aquí el "schema" no vive en un servidor de bases de datos separado: vive en tu repositorio de código, se versiona con git y genera la interfaz que tus editores usarán a diario. Eso cambia fundamentalmente quién controla la evolución del contenido: no es el equipo de producto ni el de marketing, es el equipo de ingeniería, y por eso la disciplina importa tanto.
---
Por Qué el Enfoque Tradicional de CMS Falla Aquí
La sabiduría convencional dice: elige un headless CMS, mapea unos campos, consulta contenido, listo.
Ese encuadre hace que Sanity parezca una commodity — un clon de Contentful con un admin más bonito.
La verdad incómoda: *el producto real de Sanity es la combinación que ningún otro CMS mainstream ofrece junta*:
Una base de datos de contenido consultable en tiempo real (Content Lake), no una base de datos CMS al estilo WordPress.
Un modelo de esquema-as-código que genera tu interfaz de editor (el Studio).
Texto enriquecido estructurado (Portable Text) en lugar de blobs de HTML.
Un Studio open-source (MIT) que tú posees y puedes extender.
El impacto que la mayoría pasa por alto: cada acción en el Studio es una mutación que se propaga en tiempo real a los clientes conectados. Por eso los drafts, las previews y la colaboración multi-editor funcionan sin que tú construyas una capa de sincronización.
Compara con WordPress (MySQL + sin push en tiempo real) o Contentful (REST/GraphQL pull-based). La implicación es clara: Sanity te deja construir features como live preview o presencia editorial sin atornillar websockets a mano. Es la diferencia entre montar un servidor de WebSocket, gestionar sesiones y reconciliar estados de documentos a mano, y recibir la actualización directamente del cliente oficial.
Piensa en lo que eso significa para el ciclo de desarrollo. En un CMS tradicional, cada feature nueva que depende del estado "mientras escribo" exige una planificación separada: un endpoint de draft, un sistema de caché invalidada por documento, un mecanismo de auth para editores. En Sanity, esa capa ya existe y es el comportamiento por defecto. El coste percibido de "pasar a Sanity" se reduce drásticamente cuando te das cuenta de que no estás sustituyendo un CMS por otro: estás eliminando una categoría entera de infraestructura.
❌ Enfoque débil: "Es un CMS. Defino dos fields, una API call, y a vivir."
✅ Enfoque fuerte: "Es infraestructura. El esquema es mi contrato. GROQ sustituye resolvers. El Studio es código que poseo."
Este segundo enfoque tiene una consecuencia indirecta que merece mención: cambia las conversaciones internas del equipo. Cuando el esquema es código, los debates sobre "qué campos necesita una página" se convierten en code reviews con criterios técnicos explícitos. Nadie puede "abrir el admin y añadir un campo" al vuelo — que es exactamente la disciplina que la mayoría de las organizaciones necesitan y no tienen.
---
La Evidencia: Qué Hay Realmente Debajo del Capó
Schema-as-code: tu fichero genera la UI del editor
En WordPress, los content types viven en PHP y la base de datos. En Sanity, *el fichero TypeScript del esquema genera la interfaz del editor, la validación y la superficie de API en un solo lugar*.
```typescript
// schemas/post.ts
import { defineType, defineField } from 'sanity'
export const post = defineType({
name: 'post',
title: 'Post',
type: 'document',
fields: [
defineField({
name: 'title',
title: 'Título',
type: 'string',
validation: (rule) => rule.required().max(90),
}),
defineField({
name: 'slug',
title: 'Slug',
type: 'slug',
options: { source: 'title' },
}),
defineField({
name: 'publishedAt',
title: 'Publicado el',
type: 'datetime',
validation: (rule) => rule.required(),
}),
defineField({
name: 'author',
title: 'Autor',
type: 'reference',
to: [{ type: 'author' }],
}),
defineField({
name: 'body',
title: 'Cuerpo',
type: 'array',
of: [{ type: 'block' }],
}),
],
})
```
Debido a que los modelos se versionan con git y se revisan en PRs, la evolución del contenido se vuelve un proceso controlado. El lado negativo es la disciplina: sin `ALTER TABLE`, evolucionar un modelo significa campos aditivos, patches y deprecación cuidadosa. En la práctica, esto significa:
1. Nunca borres un campo: añade el nuevo y depreca el viejo en el schema, documentando el cambio en el commit.
2. Los patches reemplazan los UPDATEs: si necesitas transformar datos existentes (por ejemplo, migrar un campo `bodyHtml` a Portable Text), escribes una migración que los parchee uno a uno o en lotes.
3. El code-review es tu ORM: cada cambio de esquema pasa por la misma revisión que cualquier otro cambio de código, lo que fuerza documentación implícita.
Los equipos que se saltan este paso acumulan campos muertos y referencias rotas. He visto proyectos reales con doce campos `legacy_*` que nadie se atreve a tocar porque "no sabemos quién los usa". En Sanity no hay herramientas de administración de base de datos que permitan "arreglarlo rápido" — lo que es un incentivo poderoso para hacerlo bien desde el principio.
Portable Text: el diferenciador infravalorado
La mayoría de los headless CMS guardan el texto enriquecido como HTML opaco o Markdown — que no puedes consultar ni transformar estructuralmente.
Portable Text almacena el contenido como un array JSON de bloques con marks y anotaciones, de manera que el mismo contenido se puede renderizar como HTML, texto plano o componentes React. Y puedes incluso consultar dentro del texto. La diferencia práctica es enorme: un blob de HTML es una caja negra; Portable Text es una estructura de datos que puedes manipular con las mismas herramientas que usarías para cualquier otro JSON.
```tsx
// components/PortableText.tsx
import { PortableText } from '@portabletext/react'
const myPortableTextComponents = {
marks: {
internalLink: ({ children, value }) => (
<a href={`/${value.slug.current}`}>{children}</a>
),
highlight: ({ children }) => (
<mark className="bg-yellow-100">{children}</mark>
),
},
}
export function BlogPostContent({ body }) {
return <PortableText value={body} components={myPortableTextComponents} />
}
```
Piensa en los casos de uso que un blob HTML hace inviables:
Extraer metadatos: con GROQ puedes hacer `body[].children[].text` para obtener el texto plano de un post y generar automáticamente una meta description o un índice de contenidos.
Renderizado multiformato: el mismo contenido puede alimentar un sitio web, un email, un feed RSS o un PDF, cada uno con sus propio `components` y transformaciones.
Análisis de contenido: puedes consultar cuántos posts usan un callout concreto o una anotación determinada, para decisiones editoriales informadas por datos.
Esto ya se ha spin-out como spec open independiente usada más allá de Sanity — señal de lo influyente que se volvió la idea. Cuando una especificación de serialización de texto trasciende el proyecto que la creó, es buena señal de que resolvía un problema real que afectaba a toda la industria.
GROQ: un lenguaje de consulta real, no una ocurrencia
Los equipos que llegan desde GraphQL asumen que necesitan una capa de resolvers. Las proyecciones y joins de GROQ colapsan eso en un solo string.
```groq
*[_type == "post" && publishedAt < now()]
| order(publishedAt desc) {
title,
"slug": slug.current,
"author": author->name,
"excerpt": pt::text(body)
}
```
Es expresivo — pero es sintaxis nueva, y la documentación a veces es escueta. Los operadores que más rinden al principio son pocos y se aprenden rápido: los filtros entre corchetes `[_type == "post"]`, el pipe `|` para ordenar o proyectar, el operador de referencia `->` para hacer joins, y los helpers como `pt::text()` para extraer texto plano de Portable Text. Con esos cinco conceptos cubres el 90% de las queries de una aplicación típica.
El flujo práctico es iterar en el playground Vision dentro del Studio antes de pegar las queries en el código de la app. Vision te permite ejecutar queries contra tu dataset real, ver la respuesta en JSON y ajustar la proyección sin necesidad de redeploy. Es lo más parecido a tener un `psql` interactivo para tu contenido.
Hay un matiz que conviene destacar: GROQ sustituye a los resolvers de GraphQL, pero no es un reemplazo directo para toda la lógica de negocio. Cálculos complejos, normalizaciones de datos o transformaciones que dependen del estado de varias consultas deben seguir viviendo en tu capa de aplicación. GROQ es extremadamente bueno en lo suyo — filtrar, ordenar y proyectar documentos — y muy malo en lo que no es su trabajo. Saber distinguir una de otra te ahorra query strings inmantenibles.
El Studio es una codebase React que posees
Por ser MIT y extensible, puedes construir inputs personalizados, tools propias e incluso embeber el Studio en una aplicación mayor.
```tsx
// custom-inputs/SlugPreview.tsx
import { useFormValue } from 'sanity'
import { defineField } from 'sanity'
export function SlugPreviewInput(props) {
const title = useFormValue(['title'])
return (
<div>
{props.renderDefault(props)}
<p className="text-sm text-gray-500">
Preview: /blog/{String(title).toLowerCase().replace(/\s+/g, '-')}
</p>
</div>
)
}
```
Pero esto es una espada de doble filo: *sin skills de React, pagas un coste de mantenimiento continuo* que un admin alojado te ocultaría. No es una excepción: es el coste real de la propiedad. Dicho esto, la mayoría de las extensiones que necesitas — inputs personalizados, document actions, asset sources — requieren un nivel de React intermedio, no senior. Estamos hablando de componentes que reciben props, usan algún hook de Sanity como `useFormValue` y devuelven JSX. Nada de state management global ni arquitectura compleja.
El beneficio más tangible de poseer el Studio aparece en los flujos editoriales que no encajan en el molde genérico: un botón de "publicar + notificar en Slack", un input que valida el slug contra una API externa, un custom dashboard con métricas de contenido. Con otros CMS alojados, estas piezas exigen abrir tickets de soporte o esperar a que las añadan al roadmap. Con Sanity, las construyes tú en una tarde y las despliegas con el mismo CI que el resto de tu aplicación.
---
Análisis: Qué Significa Esto Para Ti, Ahora
La colaboración en tiempo real está integrada en la experiencia de edición. Varios redactores pueden trabajar en el Studio simultáneamente y los clientes conectados reciben actualizaciones vía la capa de API — sin que construyas nada de sync.
Eso te permite construir features que con cualquier otro CMS requerirían infraestructura paralela: live preview conectado al draft, presencia editorial, contenido que reacciona a estado.
Considera el caso típico de transición: un equipo con un flujo editorial establecido que migra desde un CMS tradicional. La curva de aprendizaje no está en la sintaxis — GROQ se aprende en días — sino en el cambio de mentalidad sobre quién es dueño de qué. En un CMS tradicional, el modelo de contenido es territorio del equipo de producto; en Sanity, es territorio del equipo de ingeniería. Si el equipo de producto sigue esperando "abrir el admin y crear un campo", la fricción será constante. Si se adapta a un flujo de PRs y code-review para cambios de esquema, el sistema se convierte en una ventaja competitiva.
Y sobre el miedo legítimo al lock-in: GROQ, Portable Text y el Studio open-source reducen el lock-in en los bordes, y el contenido es accesible vía la API pública. Pero el Content Lake alojado es infraestructura propietaria. La migración y el riesgo de vendor merecen una respuesta clara, no un dismissal.
¿Es overkill para un sitio web de marketing simple? Sí. Para un producto con contenido estructurado, colaboración editorial y previews, es la diferencia entre construir el sync a mano o no.
---
El Patrón de los 5 Compromisos del Content Lake
Este es el framework que uso en cada proyecto con Sanity. Cinco pasos, en orden estricto. No es una lista de buenas prácticas opcionales: cada paso se apoya en el anterior, y saltarte uno compromete los siguientes.
Paso 1: Define el modelo como código antes de tocar la UI
Mapea cada content type (page, post, product, author, settings) a un fichero de schema TypeScript con field types, validación y referencias. El schema ES el contrato entre editores, API y frontend. Si lo haces bien, el Studio se genera solo.
Dedica tiempo a decidir qué es un documento propio y qué es una referencia. El error más común en los proyectos nuevos es modelar como array embebido lo que debería ser una referencia — o al revés. Una regla práctica simple: si el dato va a ser reutilizado en varios documentos o editado desde más de una sección, es una referencia. Si es parte intrínseca del documento y solo vive ahí, es un array. Este criterio, aplicado desde el primer día, evita la refactorización más dolorosa que existe en cualquier CMS.
Paso 2: Modela el texto enriquecido como Portable Text
Usa bloques con anotaciones personalizadas (enlaces internos, embeds, callouts) en lugar de strings HTML/Markdown. Así el texto sigue siendo consultable y renderizable en todos los clientes. Un blob HTML es una dead end.
La trampa habitual: migrar un post que trae HTML heredado y pegar el HTML directamente en un campo Portable Text "para no perder el formato". Eso te regala los problemas de ambos mundos: no puedes consultarlo, no puedes renderizarlo en otro cliente y además pierdes la validación. La opción correcta, aunque más lenta al principio, es convertir ese HTML a bloques con un transformer como `html-to-portable-text`, y depurar los casos raros (tablas, iframes, estilos inline) uno a uno. El coste inicial es real, pero es la inversión más rentable del proyecto entero.
Paso 3: Aprende GROQ a propósito
Practica filtros, proyecciones y joins de referencias en la herramienta Vision del Studio antes de cablear queries en la aplicación. GROQ sustituye tanto la llamada a la API como la capa de resolvers que construirías aparte. Mantén las queries pequeñas y componibles.
Un hábito que recomiendo: guarda las queries "frecuentes" de cada proyecto en un fichero `src/queries.ts` con nombres descriptivos y comentarios sobre el documento que devuelven. GROQ no es un lenguaje que escribas a diario, y la memoria fresca de por qué escribiste una proyección de tres líneas se evapora en semanas. Documentarlo en el lugar donde vive el código —no en una doc externa— es lo que diferencia a los equipos que mantienen Sanity a largo plazo de los que acumulan queries crípticas.
Paso 4: Extiende el Studio para encajar tu flujo editorial
Crea inputs personalizados, document actions (ej. "publicar + notificar"), asset sources y control de acceso por roles. La UI es una codebase React que posees, no un admin bloqueado. Es la diferencia entre un CMS que los editores odian y uno que no notan.
El objetivo declarado: que el Studio desaparezca como fricción. Si tus editores pasan más tiempo pensando en cómo guardar contenido que en qué van a publicar, el Studio está mal. La mayoría de las extensiones que resuelven esto son pequeñas — un input de slug con preview, una action que valida todo antes de publicar — pero su efecto acumulado en el día a día del equipo editorial es enorme.
Paso 5: Conecta el frontend con actualizaciones incrementales
Usa el client SDK con on-demand revalidation o webhooks para que los cambios de contenido se propaguen sin rebuild completo. Cablea un flujo draft/preview usando los IDs de documento draft.
```typescript
// lib/sanity-client.ts
import { createClient } from 'next-sanity'
export const client = createClient({
projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID,
dataset: 'production',
apiVersion: '2026-03-01',
useCdn: false,
})
// Actualización incremental tras publicar
await client.patch(postId)
.set({ published: true })
.commit()
```
El patrón draft/preview merece una mención aparte porque es donde Sanity brilla por diseño. En un CMS tradicional, la preview exige montar un entorno de staging, sincronizar la base de datos y esperar. En Sanity, el draft es solo un documento más con un ID prefijado (`drafts.<id>`), y conectar la preview significa consultar ese documento a través de una ruta protegida. Los editores ven tus componentes reales con datos reales en el momento en que escriben. Esa capacidad, que con otros proveedores requeriría una infraestructura dedicada, aquí es el comportamiento por defecto.
---
La Verdad Que Nadie Te Dice
El mayor fallo con Sanity no es el editor ni la velocidad de la API. Es modelar contenido sin disciplina y después intentar arreglarlo con reuniones en vez de parches versionados.
Hay un paralelismo interesante con lo que está ocurriendo en el desarrollo de software en general: cuando el contenido se trata como infraestructura, las mismas prácticas que han hecho fiable al software — versionado, code-review, migraciones controladas— se aplican a los datos. Y el resultado es que el sistema de contenido se vuelve predecible, justo lo que un equipo editorial necesita cuando el contenido ya es el producto. No se trata de la herramienta en abstracto: se trata de que la modalidad de trabajo que impone (código, PRs, parches) alinea el contenido con el resto de la ingeniería.
Trátalo como infraestructura. El esquema es código. GROQ es tu SQL. El Studio es una app React que mantienes. Content Lake es tu base de datos en tiempo real.
Haz eso y tendrás un sistema de contenido que los editores no notan y los desarrolladores pueden evolucionar con code-review.
Trátalo como WordPress y tendrás un modelo de contenido que tirar a la basura en seis meses.
*La diferencia no está en la herramienta. Está en el compromiso que haces al modelar. *
Sanity es la infraestructura que el contenido necesita cuando el contenido ya es el producto.
Lee el artículo completo en brianmenagomez.com
Más sobre mis servicios en brianmenagomez.com
Herramientas: Conversor IAE CNAE · Gestorias cerca de ti · Calculadora IRPF

