El 90% de tus Consultas GROQ Envían Datos que Nunca Usas
Cada vez que ejecutas *[_type == 'post'] en Sanity.io, estás enviando kilobytes de datos innecesarios al cliente.
Metadatos internos. Referencias sin resolver. Campos ocultos del sistema. Todo viaja por la red y se parsea en el navegador.
La mayoría asume que GROQ es solo sobre velocidad de consulta. Que si la query responde en 50ms, todo va bien.
El problema real no es la velocidad de la query. Es el tamaño del payload que viaja hasta el cliente.
El 90% de los desarrolladores con Sanity.io están enviando entre 3 y 5 veces más datos de los necesarios. Y esto tiene consecuencias concretas: tiempos de carga más lentos, peor rendimiento en Core Web Vitals, y mayor consumo de recursos tanto en servidor como en cliente.
Voy a mostrarte cómo escribir consultas GROQ que envían exactamente lo que necesitas. Nada más.
Por Qué tu Arquitectura Actual Es Ineficiente
La práctica más común en proyectos con Sanity.io es usar consultas que devuelven documentos completos.
Esta consulta devuelve TODO el documento. Cada campo. Cada referencia. Cada metadato interno. Para un blog simple puede no parecer grave. Pero cuando tienes 50 posts, cada uno con 15 campos y 3 referencias, estás transfiriendo datos que tu componente nunca va a usar.
Los problemas concretos:
1. Over-fetching sistemático. Estás pidiendo campos que no existen en el template, campos que decides no renderizar, referencias que nunca accedes. Cada kilobyte de más es deuda técnica que pagáis en rendimiento.
2. joins descontrolados. Cuando necesitas datos relacionados, muchos desarrolladores hacen joins sin proyecciones específicas. Un autor con 30 posts genera respuestas masivas porque cada post incluye el autor completo con todos sus campos, y cada autor incluye sus 30 posts de nuevo.
3. Filtros en el cliente en lugar del servidor. Después de recibir el documento completo, filtran, ordenan y limitan en JavaScript. Esto desperdicia ancho de banda y fuerza al cliente a procesar datos que el servidor podría eliminar antes de enviar.
La consecuencia: payloads de 500KB cuando podrían ser 80KB. Tiempo de parseo en el cliente que retrasa el First Contentful Paint. Más trabajo para el bundle de tu aplicación.
El Patrón de Proyecciones Explícitas
Las proyecciones GROQ son análogas a SELECT en SQL. En lugar de SELECT *, especificas exactamente los campos que necesitas.
La diferencia en tamaño de respuesta es drástica. Un documento post típico en Sanity puede pesar 8-12KB con todos los campos. Una proyección de solo los campos necesarios puede reducirlo a 1-2KB por documento.
Estructura de una Proyección GROQ
Puedes anidar proyecciones para objetos complejos:
Esta estructura solo devuelve los campos explícitamente listados. Ni más ni menos.
Por Qué Funciona
Cuando Sanity ejecuta una proyección, solo consulta los campos especificados en el schema. No carga campos no utilizados. No serializa referencias internas. No incluye metadatos del sistema a menos que los pidas explícitamente con _updatedAt o _rev.
El resultado: queries más rápidas en el servidor (menos datos que procesar) y menos datos que transferir al cliente.
Filtros Server-Side: El Error de Procesar en el Cliente
La segunda optimización más ignorada es filtrar datos en el servidor, no en el cliente.
Aquí tienes una comparación directa:
Operadores GROQ para Filtros Avanzados
GROQ soporta operadores lógicos completos:
El filtrado en servidor elimina datos antes de transferirlos. Esto significa menos payload, menos tiempo de red, menos trabajo de parseo en el cliente.
Joins Selectivos: Controlando la Explosión de Datos
Los joins en GROQ son potentes pero peligrosos. Sin control, pueden duplicar datos exponencialmente.
El Problema de los Joins Sin Límites
Si un autor tiene 50 posts, cada post incluye el autor completo. Y si cada post tiene tags, categorías, y referencias a otros posts, el payload crece exponencialmente.
El Patrón de Joins Selectivos
Este patrón tiene tres componentes:
1. Proyección explícita en la referencia. En lugar de posts: *...[0...5], especificas los campos: posts: *...[0...5]{ title, slug }.
2. Límites en arrays. [0...5] limita a los primeros 6 resultados. Ajusta según necesites.
3. Joins en una dirección. En lugar de autor → posts → autor → posts (ciclo infinito), controla la dirección: autor → posts (un nivel).
Proyecciones Cruzadas con Referencias
Este patrón te da exactamente los datos que necesitas para una vista de pedido, sin incluir campos irrelevantes del customer o product.
El Patrón de Paginación Eficiente
Para listas grandes, la paginación server-side es crítica.
Explicación:
| order(publishedAt desc)ordena los resultados antes de limitar[0...19]toma los primeros 20 elementos (índices 0-19)- Para la página siguiente:
[20...39]
La paginación en servidor evita descargar miles de registros cuando solo necesitas 20. También evita timeouts en documentos muy grandes.
El Framework de 5 Fases para Reducir tu Payload
Este es el sistema que uso en cada proyecto con Sanity.io.
Fase 1: Auditoría de Consultas Existentes
Abre tu código y lista todas las queries GROQ. Para cada una, pregúntate:
- ¿Qué campos usa realmente el componente que consume estos datos?
- ¿Hay campos en el schema que nunca se renderizan?
- ¿Qué referencias se acceden realmente?
Crea una tabla: Query | Campos Usados | Campos Devueltos | Ratio de Eficiencia.
Fase 2: Implementa Proyecciones Explícitas
Reemplaza cada *[_type == "x"] por *[_type == "x"]{ campo1, campo2 }.
Si la lista es larga, usa un archivo de constantes para mantener consistencia:
Fase 3: Mueve los Filtros al Servidor
Identifica todos los .filter() y .find() en el cliente que procesan datos de Sanity. Conviértelos en filtros GROQ.
Usa operadores &&, ||, y ! para combinar condiciones. Cuanto más específico, mejor.
Fase 4: Controla los Joins
Para cada referencia, responde:
- ¿Necesito los datos completos del documento referenciado o solo campos específicos?
- ¿Hay límite en el número de resultados que necesito?
- ¿Evito ciclos de referencias autor → post → autor → post?
Aplica proyecciones y límites en cada nivel de join.
Fase 5: Implementa Paginación
Para cualquier consulta que pueda devolver más de 20-50 resultados, implementa paginación con rangos [start...end].
Configura controles en el cliente para navegar entre páginas sin recargar todos los datos.
Impacto Real: Qué Esperar
Después de aplicar estas optimizaciones, los resultados típicos son:
- Payload reducido entre 40% y 60% para páginas con múltiples documentos
- Tiempo de parseo JSON reducido proporcionalmente (menos datos = parseo más rápido)
- Mejora en First Contentful Paint para usuarios en conexiones lentas
- Menor carga en la API de Sanity al reducir volumen de datos transferidos
No son mejoras teóricas. Son cambios medibles en las Network DevTools de tu navegador.
El Siguiente Paso
Abre tu proyecto. Elige la consulta más usada (probablemente el feed principal o lista de productos). Aplica una proyección explícita.
Mide el tamaño del payload antes y después. Compara.
Si ves una diferencia significativa, aplica el mismo proceso al resto de tus consultas.
La optimización de GROQ no es micro-optimización. Es arquitectura correcta. Cada kilobyte que no transfieres es tiempo que no pierdes y datos que no procesas.
Tu API de Sanity responde más rápido de lo que crees. El problema nunca fue la velocidad de la query. Era el tamaño de lo que enviaba después.
Artículos relacionados
- Sanity.io en Producción: El CMS que Más del 90% de Developers Configura Mal
- Next.js en Producción: La Arquitectura que Separa los Proyectos que Escalan de los que Explotan
- Schema Design Patterns en Sanity.io: Cómo Construir Schemas que Sobreviven a Tus Migraciones
- ISR Strategies en Next.js: La Decisión de Renderizado que Separa el Rendimiento del Caos
- Vercel en Producción: La Guía Definitiva de Deployment que Nadie Escribe
---
¿Quieres recibir contenido como este cada semana? Suscríbete a mi newsletter

