El Stack Vercel + Next.js + Supabase + Claude API: Sin CMS Necesario
He estado construyendo sitios web con plataformas CMS headless durante años. Contentful, Sanity, Strapi -- lo que sea, lo he integrado. Pero a finales de 2025, comencé a notar un patrón: para una cantidad creciente de proyectos, no estaba recurriendo a un CMS en absoluto. En su lugar, estaba lanzando aplicaciones full-stack con Next.js en Vercel, Supabase para datos y autenticación, y la API de Claude para cualquier inteligencia de contenido que necesitara. Sin proveedor de CMS. Sin interfaz de modelado de contenido. Sin licencias mensuales por usuario.
No se trata de ser contrario. Hay absolutamente proyectos donde un CMS headless es la opción correcta -- construimos muchos de esos en Social Animal (consulta nuestro trabajo de desarrollo de CMS headless). Pero hay una clase específica de aplicación donde este stack sin proveedor no solo es viable, es mejor. Déjame mostrarte exactamente cómo funciona, cuándo usarlo y cómo configurarlo desde cero.
Tabla de Contenidos
- Por qué los desarrolladores están abandonando el CMS
- El Stack de un vistazo
- Configurar tu proyecto Next.js en Vercel
- Supabase como tu backend: Auth, base de datos y almacenamiento
- Integrando la API de Claude para inteligencia de contenido
- Construyendo una interfaz de administración personalizada
- Costos reales: lo que realmente te cuesta este stack
- Cuándo deberías seguir usando un CMS
- Lista de verificación de implementación en producción
- Preguntas frecuentes
Por qué los desarrolladores están abandonando el CMS
Seamos honestos sobre lo que te da un CMS: una interfaz para que personas no técnicas editen contenido, una capa de datos estructurada, tal vez gestión de medios, y una API para obtenerlo todo. Eso es genuinamente valioso cuando tienes un equipo de marketing publicando posts cada día.
Pero esto es lo que sigo viendo en 2026:
- Productos SaaS donde el "contenido" son datos generados por el usuario, no copia editorial
- Herramientas internas donde el equipo es técnico enough para editar una base de datos directamente o usar un panel de administración ligero
- Aplicaciones nativas de IA donde el contenido se genera, resume o transforma sobre la marcha
- Startups que no pueden justificar $300-500/mes por un CMS cuando tienen tres usuarios
Para estos proyectos, un CMS es una carga innecesaria. Estás pagando por características de modelado de contenido que no usarás, gestionando claves de API para un servicio que es básicamente un envoltorio de base de datos sofisticado, y lidiando con la complejidad de webhooks para mantener todo sincronizado.
¿La alternativa? Poseer tu capa de datos completamente. Supabase te da Postgres (una base de datos real, no un almacén de contenido propietario), autenticación, almacenamiento de archivos y suscripciones en tiempo real. Claude maneja la capa de inteligencia. Next.js y Vercel manejan todo lo demás.
El Stack de un vistazo
| Capa | Tecnología | Rol | Precios 2026 (Inicial) |
|---|---|---|---|
| Frontend y API | Next.js 15 (App Router) | UI, Server Components, Route Handlers | Gratis (código abierto) |
| Hosting y Edge | Vercel | Implementación, CDN, Funciones sin servidor | Capa gratis / $20/mes Pro |
| Base de datos y Auth | Supabase | Postgres, Row Level Security, Auth, Storage | Capa gratis / $25/mes Pro |
| Capa de IA | Claude API (Anthropic) | Generación de contenido, resumen, clasificación | Pago por token (~$3/$15 por 1M tokens para Sonnet 4) |
| Admin UI | Personalizado (React + Supabase) | Gestión de contenido para tu equipo | $0 (lo construyes tú) |
Costo total para una aplicación en producción con tráfico moderado: $45-100/mes. Compáralo con una configuración típica de CMS headless donde solo el CMS podría costarte $99-500/mes antes de pagar ni siquiera por el hosting.
Configurar tu proyecto Next.js en Vercel
Asumo que tienes Node.js 20+ y una cuenta en Vercel. Si eres nuevo en Next.js, nuestro equipo ha escrito extensamente sobre esto en nuestra página de capacidad de desarrollo Next.js.
npx create-next-app@latest my-app --typescript --tailwind --app --src-dir
cd my-app
Next.js 15 con App Router es la base aquí. Estamos usando Server Components por defecto, lo que significa que la mayoría de nuestras búsquedas de datos ocurren en el servidor -- sin claves de API expuestas, sin spinners de carga del lado del cliente para contenido inicial.
Aquí está mi estructura de proyecto típica para este stack:
src/
├── app/
│ ├── (public)/ # Páginas de marketing, blog
│ ├── (dashboard)/ # Área de administración autenticada
│ │ ├── layout.tsx # Wrapper de verificación de auth
│ │ ├── posts/
│ │ ├── media/
│ │ └── settings/
│ ├── api/
│ │ ├── ai/ # Rutas de la API de Claude
│ │ └── webhooks/ # Hooks de tiempo real de Supabase
│ └── layout.tsx
├── lib/
│ ├── supabase/
│ │ ├── client.ts # Cliente del navegador
│ │ ├── server.ts # Cliente del servidor
│ │ └── admin.ts # Cliente de rol de servicio
│ ├── claude.ts # Envoltorio del SDK de Anthropic
│ └── utils.ts
├── components/
└── types/
Variables de entorno
Necesitarás estos en tu .env.local:
NEXT_PUBLIC_SUPABASE_URL=your-project-url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
SUPABASE_SERVICE_ROLE_KEY=your-service-key
ANTHROPIC_API_KEY=sk-ant-...
Implementar en Vercel
Envía a GitHub. Conecta el repositorio en Vercel. Agrega tus variables de entorno. Listo. No voy a extenderme en esto -- la DX de Vercel para la implementación de Next.js es la mejor de la industria y probablemente ya sabes cómo funciona.
Una cosa que vale la pena notar: usa Vercel's Edge Config si necesitas feature flags o configuración que se actualice sin reimplementar. Es algo pequeño pero reemplaza otro herramienta SaaS.
Supabase como tu backend: Auth, base de datos y almacenamiento
Aquí es donde ocurre la magia. Supabase no es solo "Firebase pero Postgres" -- es una plataforma backend completa que realmente posees. Tus datos viven en una base de datos PostgreSQL estándar. Si alguna vez quieres irte, haces pg_dump y te vas. Intenta hacer eso con un CMS propietario.
Esquema de base de datos
Digamos que estás construyendo una aplicación impulsada por contenido (el tipo de cosa para la que normalmente recurrirías a un CMS). Aquí hay un esquema que maneja artículos, medios y taxonomía básica:
-- Habilitar generación de UUID
create extension if not exists "uuid-ossp";
-- Tabla de contenido (reemplaza tu modelo de contenido de CMS)
create table public.posts (
id uuid default uuid_generate_v4() primary key,
title text not null,
slug text unique not null,
body text, -- Contenido Markdown
excerpt text,
status text default 'draft' check (status in ('draft', 'published', 'archived')),
author_id uuid references auth.users(id),
featured_image text, -- Ruta de Supabase Storage
metadata jsonb default '{}', -- Campos flexibles, sin necesidad de migración
published_at timestamptz,
created_at timestamptz default now(),
updated_at timestamptz default now()
);
-- Tags / taxonomía
create table public.tags (
id uuid default uuid_generate_v4() primary key,
name text unique not null,
slug text unique not null
);
create table public.post_tags (
post_id uuid references public.posts(id) on delete cascade,
tag_id uuid references public.tags(id) on delete cascade,
primary key (post_id, tag_id)
);
-- Row Level Security
alter table public.posts enable row level security;
-- Cualquiera puede leer posts publicados
create policy "Public can read published posts"
on public.posts for select
using (status = 'published');
-- Los usuarios autenticados pueden gestionar sus propios posts
create policy "Authors can manage own posts"
on public.posts for all
using (auth.uid() = author_id);
Esa columna metadata jsonb es clave. Te da la flexibilidad de los campos personalizados de un CMS sin necesidad de ejecutar migraciones cada vez que el equipo de marketing quiere un nuevo campo. ¿Necesitas una descripción SEO? metadata->>'seo_description'. ¿Necesitas un override de imagen Open Graph? metadata->>'og_image'. Es sin esquema donde necesitas flexibilidad, estructurado donde necesitas integridad.
Configuración de Auth
Supabase Auth maneja todo. Email/contraseña, magic links, OAuth con Google/GitHub -- todo está integrado.
// lib/supabase/server.ts
import { createServerClient } from '@supabase/ssr'
import { cookies } from 'next/headers'
export async function createClient() {
const cookieStore = await cookies()
return createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll() {
return cookieStore.getAll()
},
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value, options }) =>
cookieStore.set(name, value, options)
)
},
},
}
)
}
Almacenamiento de archivos
Supabase Storage reemplaza cualquier biblioteca de medios que tu CMS tuviera. Crea un bucket llamado media, configura una política, y tienes un almacén de archivos compatible con S3 con URLs de CDN automáticas.
// Subir un archivo
const { data, error } = await supabase.storage
.from('media')
.upload(`posts/${slug}/${file.name}`, file, {
cacheControl: '3600',
upsert: false,
})
// Obtener URL pública
const { data: { publicUrl } } = supabase.storage
.from('media')
.getPublicUrl(`posts/${slug}/${file.name}`)
Integrando la API de Claude para inteligencia de contenido
Aquí es donde el stack de 2026 diverge más de la web dev tradicional. La API de Claude no es solo un chatbot -- es una capa de inteligencia que puede reemplazar categorías enteras de plugins de CMS y servicios de terceros.
Aquí está lo que la estoy usando en producción:
- Generación automática de metadatos SEO a partir del contenido del post
- Resumen de contenido para extractos y tarjetas sociales
- Clasificación de contenido y auto-etiquetado
- Búsqueda inteligente que entiende la intención, no solo palabras clave
- Asistencia de borrador para autores de contenido
Configurar el SDK de Anthropic
npm install @anthropic-ai/sdk
// lib/claude.ts
import Anthropic from '@anthropic-ai/sdk'
const anthropic = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY!,
})
export async function generateSEOMetadata(content: string, title: string) {
const message = await anthropic.messages.create({
model: 'claude-sonnet-4-20250514',
max_tokens: 1024,
messages: [
{
role: 'user',
content: `Dado este título y contenido del artículo, genera metadatos SEO.
Título: ${title}
Contenido: ${content.slice(0, 3000)}
Responde solo con JSON:
{
"seo_title": "Título de 50-60 caracteres con palabra clave principal",
"seo_description": "Descripción meta de 120-160 caracteres",
"excerpt": "Hook de 1-2 oraciones para compartir en redes sociales",
"suggested_tags": ["tag1", "tag2", "tag3"]
}`,
},
],
})
const text = message.content[0].type === 'text' ? message.content[0].text : ''
return JSON.parse(text)
}
export async function classifyContent(content: string, existingTags: string[]) {
const message = await anthropic.messages.create({
model: 'claude-sonnet-4-20250514',
max_tokens: 256,
messages: [
{
role: 'user',
content: `Clasifica este contenido en las etiquetas más relevantes de la lista existente. Puedes sugerir hasta 2 etiquetas nuevas si nada encaja.
Etiquetas existentes: ${existingTags.join(', ')}
Contenido: ${content.slice(0, 2000)}
Responde con JSON: { "tags": ["tag1", "tag2"], "new_tags": ["maybe-new"] }`,
},
],
})
const text = message.content[0].type === 'text' ? message.content[0].text : ''
return JSON.parse(text)
}
Ruta API para características de IA
// app/api/ai/seo/route.ts
import { NextRequest, NextResponse } from 'next/server'
import { createClient } from '@/lib/supabase/server'
import { generateSEOMetadata } from '@/lib/claude'
export async function POST(request: NextRequest) {
const supabase = await createClient()
const { data: { user } } = await supabase.auth.getUser()
if (!user) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}
const { content, title } = await request.json()
try {
const metadata = await generateSEOMetadata(content, title)
return NextResponse.json(metadata)
} catch (error) {
return NextResponse.json(
{ error: 'AI generation failed' },
{ status: 500 }
)
}
}
El costo aquí es insignificante. Una llamada de generación de metadatos SEO típica usa quizá 4,000 tokens de entrada y 200 tokens de salida. Con los precios de Claude Sonnet 4 en aproximadamente $3/1M tokens de entrada y $15/1M tokens de salida, eso es aproximadamente $0.015 por llamada. Podrías generar metadatos para 1,000 artículos por $15.
Construyendo una interfaz de administración personalizada
Esta es la parte que pone nerviosa a la gente. "Si no tengo un CMS, ¿cómo editan contenido las personas no técnicas?"
Construyes una interfaz de administración simple. Y en 2026, "simple" es realmente simple. Aquí hay un componente editor de posts básico:
// app/(dashboard)/posts/[id]/editor.tsx
'use client'
import { useState } from 'react'
import { createBrowserClient } from '@supabase/ssr'
export function PostEditor({ post }: { post: Post }) {
const [title, setTitle] = useState(post.title)
const [body, setBody] = useState(post.body || '')
const [saving, setSaving] = useState(false)
const supabase = createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
)
async function save() {
setSaving(true)
const { error } = await supabase
.from('posts')
.update({
title,
body,
updated_at: new Date().toISOString(),
})
.eq('id', post.id)
setSaving(false)
if (error) alert('Save failed: ' + error.message)
}
async function generateSEO() {
const res = await fetch('/api/ai/seo', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title, content: body }),
})
const metadata = await res.json()
// Aplicar metadatos generados al post
await supabase
.from('posts')
.update({ metadata, excerpt: metadata.excerpt })
.eq('id', post.id)
}
return (
<div className="max-w-4xl mx-auto p-6">
<input
type="text"
value={title}
onChange={(e) => setTitle(e.target.value)}
className="text-3xl font-bold w-full mb-4 border-b pb-2"
/>
<textarea
value={body}
onChange={(e) => setBody(e.target.value)}
className="w-full h-96 font-mono text-sm p-4 border rounded"
/>
<div className="flex gap-4 mt-4">
<button onClick={save} disabled={saving}
className="px-4 py-2 bg-blue-600 text-white rounded">
{saving ? 'Saving...' : 'Save Draft'}
</button>
<button onClick={generateSEO}
className="px-4 py-2 bg-purple-600 text-white rounded">
✨ Generate SEO Metadata
</button>
</div>
</div>
)
}
Sí, esto es un textarea simple. En un proyecto real, cambiarías a algo como Tiptap, MDXEditor, o BlockNote para edición enriquecida. El punto es: la interfaz de administración es tu código. Controlas cada píxel, cada flujo de trabajo, cada permiso. Sin luchar contra las limitaciones de la interfaz del CMS.
Para proyectos más complejos, considera Refine o AdminJS como marcos de paneles de administración que se conectan directamente a Supabase. Te ahorrarán semanas.
Costos reales: lo que realmente te cuesta este stack
Seamos específicos con números para un sitio con mucho contenido que hace 100K pageviews/mes:
| Servicio | Nivel | Costo mensual | Lo que obtienes |
|---|---|---|---|
| Vercel | Pro | $20 | 1TB de ancho de banda, 1000 GB-hrs sin servidor |
| Supabase | Pro | $25 | Base de datos de 8GB, 250GB de ancho de banda, 100K usuarios de auth |
| Claude API | Pago por uso | ~$10-30 | ~5M tokens/mes (generación de SEO, resúmenes, búsqueda) |
| Dominio | Anual | ~$1 | Dominio .com |
| Total | $56-76/mes |
Ahora compáralo con una configuración típica de CMS headless:
| Servicio | Nivel | Costo mensual |
|---|---|---|
| Contentful | Team | $300 |
| Vercel | Pro | $20 |
| Algolia (búsqueda) | Build | $50 |
| Auth0 (auth) | Essentials | $35 |
| Total | $405/mes |
Esa es una diferencia de 5-6x. Y el stack de Supabase te da más flexibilidad, no menos.
Cuándo deberías seguir usando un CMS
Quiero ser claro y realista sobre esto. No descartes tu CMS para cada proyecto. Un CMS headless sigue siendo la opción mejor cuando:
- Grandes equipos editoriales necesitan flujos de trabajo estructurados (cadenas de aprobación, programación, roles que van más allá de RBAC básico)
- El contenido es el producto -- editores, empresas de medios, sitios de documentación con cientos de contribuidores
- Necesitas edición visual -- algunas plataformas de CMS ofrecen vista previa en vivo y constructores visuales que tomaría meses replicar
- Entrega multicanal -- si el mismo contenido alimenta un sitio web, aplicación móvil, señalización digital y correo electrónico, el modelo de contenido estructurado del CMS se justifica
- Localización a escala -- las plataformas de CMS como Contentful y Sanity tienen flujos de trabajo i18n maduros
Seguimos construyendo muchos proyectos de CMS headless en Social Animal. Si eso es lo que tu proyecto necesita, ponte en contacto con nosotros. Pero para la categoría creciente de aplicaciones donde no lo es, deja de pagar por ello.
Lista de verificación de implementación en producción
Antes de enviar este stack a producción, repasa esta lista:
- Políticas de Row Level Security probadas para cada tabla (el simulador de políticas de Supabase ayuda aquí)
- Limitación de tasa en rutas de la API de Claude (usa el limitador de tasa
@vercel/edgede Vercel o upstash/ratelimit) - Validación de entrada en todas las rutas de la API (Zod es tu amigo)
- Error boundaries en tu árbol de React para fallos de IA (Claude ocasionalmente agotará el tiempo de espera)
- Estrategia de caché -- usa
unstable_cacheorevalidateTagen Next.js para páginas respaldadas por base de datos - Monitoreo -- Vercel Analytics para rendimiento, Supabase Dashboard para métricas de base de datos, Anthropic Console para uso de API
- Estrategia de copia de seguridad -- Supabase Pro incluye copias de seguridad diarias, pero también configura replicación lógica o cron
pg_dumppara mayor tranquilidad - Encabezados de Content Security Policy configurados en
next.config.js - Optimización de imágenes -- usa el componente
<Image>de Next.js con URLs de Supabase Storage
Preguntas frecuentes
¿Puede Supabase realmente reemplazar un CMS headless? Para muchos casos de uso, sí. Supabase te da una base de datos PostgreSQL con una API REST y GraphQL generada automáticamente a partir de tu esquema, almacenamiento de archivos, autenticación y suscripciones en tiempo real. Lo que no te da es una interfaz de edición de contenido pulida lista para usar -- tendrás que construirla tú mismo o usar una herramienta como Refine. Si tu equipo es técnico o pequeño, este tradeoff vale absolutamente la pena.
¿Cuánto cuesta la API de Claude para un sitio web típico? Para un sitio de contenido que usa Claude para generación de metadatos SEO, resumen de contenido y clasificación básica, espera gastar $10-30/mes con uso moderado (algunas cientos de operaciones de IA). Los precios de Claude Sonnet 4 en 2026 se sitúan en aproximadamente $3 por millón de tokens de entrada y $15 por millón de tokens de salida. Una única llamada de generación de metadatos SEO cuesta aproximadamente $0.01-0.02.
¿Es este stack adecuado para aplicaciones empresariales? Depende de tu definición de empresa. Vercel y Supabase ofrecen ambos niveles empresariales con SLAs, cumplimiento de SOC 2 y soporte dedicado. El stack maneja bien el tráfico alto -- Next.js en Vercel escala automáticamente, y Supabase Pro soporta pooling de conexiones y réplicas de lectura. Para industrias pesadas en cumplimiento normativo, querrías la opción auto-hospedada de Supabase para mantener los datos en tu propia infraestructura.
¿Qué pasa con vistas previas de contenido y flujos de trabajo de borradores?
Los construyes tú. Next.js Draft Mode combinado con una columna status en tu tabla de posts te da flujos de trabajo de borrador/publicado. Para vistas previas, crea una ruta autenticada que obtenga posts independientemente del estado. Son quizá 50 líneas de código versus configurar URLs de vista previa en un panel de control de CMS.
¿Cómo manejas la edición de texto enriquecido sin un CMS?
Usa una biblioteca de editor de texto enriquecido moderno. Tiptap (construido sobre ProseMirror) es la opción más popular en 2026 -- soporta edición colaborativa, bloques personalizados, comandos de barra diagonal y accesos directos de Markdown. BlockNote es otra opción sólida con una interfaz similar a Notion. Almacena la salida como HTML, Markdown o JSON en tu columna body de Supabase.
¿Puedo migrar de un CMS headless a este stack? Absolutamente. La mayoría de las plataformas de CMS headless tienen APIs de exportación. Escribe un script de migración que extrae contenido de tu API de CMS e insértalo en tablas de Supabase. Hemos hecho esta migración para varios clientes, moviéndose de Contentful y Sanity a configuraciones respaldadas por Supabase. La parte más difícil suele ser mapear el formato de texto enriquecido propietario del CMS a HTML o Markdown estándar.
¿Qué sucede si Supabase se cae? Supabase ha tenido un tiempo de actividad sólido en 2025-2026, pero ningún servicio es perfecto. Porque tus datos viven en PostgreSQL estándar, tienes opciones: configura réplicas de lectura, mantén copias de seguridad automatizadas en S3, o incluso ejecuta una instancia standby. Si estás en el nivel auto-hospedado de Supabase, controlas la infraestructura completamente. Esto es realmente más resiliente que depender de un proveedor de CMS -- si Contentful tiene una interrupción, no puedes simplemente "cambiar a otro Contentful."
¿Debería usar este stack para un blog o sitio de marketing? Para el blog personal de un desarrollador o el sitio de marketing de una startup, este stack es perfecto. Obtienes control completo, costos mínimos y características impulsadas por IA que requerirían plugins costosos en un CMS. Para un equipo de marketing grande que publica 20+ artículos por semana con flujos de trabajo de aprobación complejos, probablemente querrías un CMS adecuado. Se trata de hacer coincidir la herramienta con el equipo. Si no estás seguro de qué enfoque se ajusta a tu proyecto, consulta nuestra página de precios o ponte en contacto para una consulta rápida.