Sanity CMS para 1,300+ Gestorías: Cómo Manejé Miles de Listados sin Morir en el Intento

Proyectos· 5 min de lectura

El Problema: Mil Negocios, Una Base de Datos, Cero Estructura

Cuando empecé con Gestorías Cerca de Mí, tenía un problema clásico de todo directorio online: ¿cómo gestiono información de 1,300+ negocios sin que cada cambio requiera un deploy?

Mi primer instinto fue usar Supabase directamente. Tenía la base de datos, tenía Next.js, tenía Vercel. ¿Qué más necesitaba?

Respuesta: mucho más.

La realidad es que un directorio no es solo datos. Necesitas:

  • Descripciones consistentes
  • Imágenes optimizadas
  • Campos relacionados (servicios, especialidades, horarios)
  • Control de versiones para cambios
  • Una forma humana de editar todo esto

Si intentas hacerlo solo con una base de datos SQL, terminas con:

  • Un administrador hecho en Next.js que nadie quiere mantener
  • Campos de texto libre donde debería haber estructura
  • Imágenes sin optimizar
  • Miedo a hacer cambios

Por Qué Elegí Sanity CMS (y No Otro)

Evaluéé tres opciones:

1. Strapi: Open source, autohospedado. Bonito en teoría, pesado en práctica.

2. Contentful: Potente pero caro. Para 1,300+ gestorías, el precio escalaba rápido.

3. Sanity: Headless, flexible, y con un modelo de precios que no te mata.

Elegí Sanity porque:

Portable Text para Descripciones Ricas

Cada gestoría tiene una descripción. Algunos negocios quieren texto simple, otros quieren listas, otros quieren enlaces internos a servicios específicos.

Con Sanity, uso Portable Text (su formato de contenido estructurado). En mi stack ves la dependencia:

```json "@portabletext/react": "^3.0.0" ```

Esto me permite que el contenido sea flexible sin ser caótico:

```typescript import { PortableText } from '@portabletext/react';

export function GestoriaDescription({ content }) { return <PortableText value={content} />; } ```

El editor (o yo mismo) puede crear descripciones ricas sin tocar código.

Imágenes Optimizadas Automáticamente

Tengo esta dependencia en mi proyecto:

```json "@sanity/image-url": "^1.0.0" ```

Sanity maneja imágenes de forma inteligente. Subo una foto de 5MB, y automáticamente me genera versiones optimizadas. En mi código:

```typescript import imageUrlBuilder from '@sanity/image-url';

const builder = imageUrlBuilder(sanityClient);

function urlFor(source) { return builder.image(source); } ```

Luego en Next.js:

```typescript <Image src={urlFor(gestorias.logo).width(400).url()} alt={gestorias.nombre} width={400} height={300} /> ```

Sin esto, habría terminado con imágenes sin optimizar, cargando lentamente, matando mi SEO.

Consultas en Tiempo Real

Mi stack usa `@sanity/client` para traer datos en tiempo real:

```json "@sanity/client": "^6.0.0" ```

En mis rutas de API o en `getStaticProps`:

```typescript import { client } from '@/sanity/client';

export async function getStaticProps({ params }) { const gestorias = await client.fetch(` *[_type == "gestorias" && slug.current == $slug][0] `, { slug: params.slug });

return { props: { gestorias }, revalidate: 3600 // ISR cada hora }; } ```

Esto es Incremental Static Regeneration. Genero páginas estáticas para SEO, pero las revalido automáticamente cuando el contenido cambia en Sanity.

La Arquitectura Actual (Commits Reales)

Mirando mis últimos commits en GitHub:

```

  • feat: implement Phases 9-11 mobile UX improvements (2f8d5c3, 12/30/2025)
  • feat: add city name detection to search functionality (57421d2, 12/30/2025)
  • feat(skills): add 8 Claude Code skills for improved implementation quality (c6a5887, 12/30/2025)

```

Estoy en fase de mejora continua. Las últimas 3 semanas he enfocado en:

1. Detección automática de ciudad: Cuando buscas "Madrid", el sistema entiende que es una ciudad, no una palabra aleatoria. 2. UX móvil: 71,895 reseñas y 1,307 gestorías, todo debe funcionar en móvil. 3. Skills en Claude Code: Uso Claude para mantener la calidad de implementación.

Números Reales

Hoy, Gestorías Cerca de Mí tiene:

  • **1,307 gestorías verificadas**
  • **71,895 reseñas reales**
  • **Stack 99% TypeScript** (calidad de código)
  • **0 issues abiertos** (backlog limpio)
  • **Última actualización**: hace 2 días

Eso no sucede por accidente. Sucede porque:

1. Sanity maneja el contenido de forma escalable 2. Supabase maneja los datos transaccionales (reseñas, búsquedas) 3. Next.js + Vercel manejan la entrega rápida 4. Cada tecnología hace una cosa bien

El Costo Real

Alguien preguntará: ¿cuánto cuesta Sanity?

Mi plan: Free tier (hasta 10,000 documentos).

Tengo 1,307 gestorías. Estoy cómodo en el free tier.

Cuando escale, pagaré. Pero hoy: $0 en Sanity.

Comparado con Contentful ($89/mes mínimo), eso es $1,068 anuales que no gasto.

Lo Que Aprendí

1. Un CMS Headless No Es Lujo, Es Necesidad

Cuando tienes más de 100 listados, necesitas separar contenido de código. Punto.

2. Portable Text Es Subestimado

La mayoría de CMS te dan campos de texto libre. Sanity te da estructura sin rigidez. Es la zona dorada.

3. ISR Es Tu Amigo

No necesito revalidar todo cada hora. Revalido solo cuando el contenido cambia. Eso es eficiencia.

4. Las Imágenes Optimizadas Importan

Mi Core Web Vitals subieron 20 puntos cuando optimicé imágenes con Sanity. No es vanidad, es SEO.

Lo Siguiente

Estoy trabajando en:

  • **Búsqueda por código postal**: Detectar automáticamente la zona del usuario
  • **Filtros avanzados**: Por servicios, precios, especialidades
  • **Integración de reseñas en tiempo real**: Traer reviews de Google y otros sitios

Todo esto es posible porque Sanity me da la estructura. Si usara SQL puro, estaría escribiendo migraciones.

El Takeaway

No construyas un directorio con solo una base de datos. Usa un CMS headless.

No es porque sea moderno. Es porque necesitas separar quién edita el contenido de quién edita el código.

Sanity no es la única opción. Pero es una buena opción si:

  • Tienes cientos de listados
  • Necesitas imágenes optimizadas
  • Quieres contenido estructurado
  • No quieres gastar $1,000+ anuales

Si construyes algo similar, pruébalo. El free tier de Sanity es generoso.

¿Preguntas? Puedes ver el código en GitHub. Todo es público.