Sanity.io no es un CMS. Es una Base de Datos de Contenido en Tiempo Real con un Editor que Escribes en TypeScript

Sanity.io no es un CMS. Es una Base de Datos de Contenido en Tiempo Real con un Editor que Escribes en TypeScript

Programming· 9 min read

El CMS que se niega a ser un CMS: el editor es MIT open source, el backend es una base de datos en tiempo real y GROQ convierte cuatro REST calls en una sola query

Cada vez que alguien dice "sanity io headless cms tutorial" lo que busca es otro Contentful. Un dashboard al que configuras clicando, una REST/GraphQL API y un compromiso entre la libertad del desarrollador y la experiencia editorial.

*Sanity invierte las tres suposiciones. *

Primero: el editor es código open source con licencia MIT que vive en tu repositorio. El modelo de contenido es TypeScript. Un campo nuevo pasa por pull request, review y CI, no por un dashboard que nadie versiona.

Segundo: el "query languaje raro" del que todo el mundo se queja — GROQ — es en realidad el superpoder del producto. Las referencias y los joins son ciudadanos de primera clase. Una sola query devuelve un post con su autor, sus tags y su excerpt.

Tercero: el mito de que headless significa que los editores tocan a ciegas es falso. La sincronización en tiempo real del Content Lake más el Visual Editing dan un loop de clica-en-el-sitio-y-edita que se acerca más a un documento colaborativo que a un CMS legacy.

¿Qué es exactamente el Content Lake y por qué no es una base de datos tradicional?

El backend de Sanity no es una base de datos SQL con tablas que normalizas. Es un servicio de contenido estructurado en tiempo real. Cuando mutas un documento, los cambios se propagan a todos los clientes conectados por WebSockets.

Eso tiene una consecuencia práctica que no parece importante hasta que lo usas: varios editores pueden trabajar sobre el mismo documento simultáneamente sin pisarse. No hay "save and pray". Es un documento colaborativo, como Google Docs.

El segundo punto gordo: el estudio de edición — Sanity Studio — es open source con licencia MIT. Lo ejecutas con:

[@portabletext/react] Unknown block type "code", specify a component for it in the `components.types` prop

Ese comando te monta un proyecto completo. El esquema, la validación y los inputs personalizados son JavaScript/TypeScript en tu repo. Puedes auto-hostearlo si quieres. Nadie te obliga a usar el dashboard alojado.

El modelo de contenido es código:

[@portabletext/react] Unknown block type "code", specify a component for it in the `components.types` prop

Fíjate en lo que acabas de hacer. Defines tu modelo como datos. Se commitea. Se reviewa. Se despliega con CI. En un CMS tradicional, ese campo `tags` lo habrías añadido en un formulario de un SaaS que nadie audita.

GROQ: el "lenguaje raro" que es en realidad la pieza central

Aquí está el punto de fricción. Todo el mundo aprende GraphQL o REST "por si acaso". GROQ es un sabor distinto. La reacción instintiva es "otro query languaje más que aprender".

La respuesta honesta es esta: GROQ cabe en una página de documentación. Está deliberadamente diseñado para bases de datos de documentos. No tiene la maquinaria de GraphQL — no hay types resolvers, ni cache de field, ni complexity limits.

Lo que sí tiene es el operador de dereferencia ->.

❌ Lo que harías en un CMS headless clásico para una página de listado:

  1. GET /posts (con paginación)
  2. Para cada post, GET /authors/:id (resolver el autor)
  3. Para cada post, GET /posts/:id/tags (resolver tags)
  4. Y luego construir el excerpt en el frontend, scrapeando el HTML

✅ Lo que haces con GROQ:

[@portabletext/react] Unknown block type "code", specify a component for it in the `components.types` prop

Una sola round trip. El filtro, el orden, el rango, el join con autor, el join con tags y el excerpt extraído del Portable Text — todo se resuelve en el servidor de Sanity.

Esto no es una optimización menor. Es la diferencia entre N+1 REST calls y una query. En una página de listado con diez posts y sus relaciones, ese es el ahorro más importante de tu stack de contenido.

La nota honesta: Sanity ofrece un GraphQL endpoint generado desde tu esquema. Existe como escape hatch. Pero es menos expresivo que GROQ — las proyecciones y la dereferencia dinámica se pierden. La ruta nativa del producto es GROQ, y es la que mejor soporte tiene.

Cómo integrarlo con Next.js App Router

La integración oficial es next-sanity, que te da sanityFetch, defineLive y Visual Editing para Next.js. Un fetch típico:

[@portabletext/react] Unknown block type "code", specify a component for it in the `components.types` prop

El Content Lake se conecta directo con React Server Components e ISR. La query se ejecuta en el servidor, se cachea, se revalida cuando toca. Sin capa intermedia.

Portable Text: un foso estratégico disfrazado de formato de datos

El cuerpo del artículo no es un string de HTML. Es un array JSON de bloques tipados, spans y marks. Sanity open-source la especificación.

❌ Modelo clásico: "body": "<p>Hola <strong>mundo</strong></p>" — el contenido es un blob de HTML que tienes que scrapear, sanear y re-escribir para cada salida (web, Markdown, app móvil).

✅ Con Portable Text renderizas con @portabletext/react:

[@portabletext/react] Unknown block type "code", specify a component for it in the `components.types` prop

El mismo JSON rinde como HTML web, como salida estilo Markdown o como vista nativa móvil sin scrapear nada. Y como es un formato abierto, tu contenido es dato que posees, no un formato propietario de un editor.

Imágenes sin pipeline aparte

El pipeline de imágenes de Sanity es URL-based y se procesa on-demand. Con @sanity/image-url:

[@portabletext/react] Unknown block type "code", specify a component for it in the `components.types` prop

Redimensionar, recortar, focal point, formato — todo por parámetros de URL. Para muchos proyectos eliminas la necesidad de una CDN de imágenes separada con su propio procesamiento. Es un pipeline menos que mantener.

El Modelo de los Cinco Escalones del Contenido-Operativo

Este es el framework que uso cuando alguien migra a Sanity en serio. Cinco escalones, en orden, del cero al sistema funcionando:

Escalón 1 — Scaffold y Vision.

npm create sanity@latest, elige un template de blog o blank, y ejecuta sanity dev. Antes de escribir una línea de frontend, familiarízate con el Studio y con la herramienta Vision — el playground de GROQ integrado. Vision es donde testeas queries en vivo contra tus datos reales. No escribas frontend hasta que sepas qué forma tiene tu dato.

Escalón 2 — Modela contenido como código.

Define respuestas post, author y category. Conéctalos con campos reference. Usa arrays de Portable Text para el rich text. Añade reglas de validación. Commitea el esquema a git. Los cambios de modelo de contenido pasan por code review como cualquier otro cambio.

Escalón 3 — Query con GROQ.

En tu app, usa @sanity/client con el tagged template groq. Itera las queries en Vision hasta que cada página necesite exactamente una round trip. Resuelve author->, tags[]->, usa pt::text() para excerpts. Menos de una query por página debería oler mal.

Escalón 4 — Renderiza en tu framework.

Fetch en React Server Components (o en cualquier backend). Renderiza Portable Text con @portabletext/react. Sirve imágenes con @sanity/image-url. Sin pipeline de imágenes aparte, sin transformación de HTML.

Escalón 5 — Cierra el loop para editores.

Despliega el Studio (alojado o self-hosted), configura roles y permisos, y activa Visual Editing. Los editores clican un elemento en el sitio en vivo y saltan directo al Studio. Cambian, guardan, y ven el cambio sincronizado en tiempo real. El decoupling frontend-backend no significa editar a ciegas — habilita un loop edición-preview más ajustado que un panel monolítico.

Respuestas a las objeciones que ya estáis pensando

"No quiero aprender GROQ — GraphQL o REST me vale."

Objeción legítima. GRoq es pequeño, lo testeas en vivo en Vision, y el payoff es una query con joins. El GraphQL existe pero es generado desde tu esquema y menos expresivo. La conclusión honesta: GROQ es la ruta nativa del producto. Ignorarlo es usar el 40% de Sanity.

"Esto es vendor lock-in — si Sanity desaparece, mi contenido queda atrapado."

El Studio es MIT. Portable Text es una spec abierta. Y sanity dataset export / import te da el JSON completo que puedes migrar a cualquier sitio. Tu contenido es tu dato, no un formato propietario.

"Sanity es overkill para un blog o una web de marketing."

La fricción real existe: un fichero de schema, un query languaje, un editor que es código. Pero la complejidad es opcional: dos document types y una query cubren un blog. El coste solo crece si y cuando las relaciones de contenido lo exigen. Y los editores ganan un loop de edición mejor que un workflow de Markdown estático.

La escala real: no es solo para desarrolladores con barba

La lista pública de clientes de Sanity incluye a Nike, National Geographic, Sonos, Puma, Cloudflare y AT&T. Esto no es un "CMS de blogs para devs hipsters". Es infraestructura de contenido usada a escala enterprise, donde la query única de GROQ y el modelo definido en código son justo lo que un equipo de ingeniería maduro necesita.

*

Son tres decisiones que tomas una vez y que cambian cómo piensas el contenido. El editor que es código que versionas. El query languaje que hace joins en una sola petición. El formato de rich text que es dato abierto.

*El real sanity.io headless cms tutorial no es "cómo configurar otro CMS". Es "cómo dejar de tratar el contenido como algo que configuras y empezar a tratarlo como código que despliegas". *

Y cuando lo ves así, GROQ deja de ser el peaje molesto y se convierte en la razón por la que no vuelves atrás.

Artículos relacionados

---

¿Quieres recibir contenido como este cada semana? Suscríbete a mi newsletter

Brian Mena

Brian Mena

Software engineer building profitable digital products: SaaS, directories and AI agents. All from scratch, all in production.

LinkedIn