Andrej Karpathy acuñó el término en febrero de 2025 para describir un modo de programar donde describes lo que quieres en lenguaje natural, el modelo genera el código y tú aceptas sin leer demasiado. Dieciocho meses después, hay suficientes proyectos en producción para separar lo que funciona de lo que genera deuda técnica silenciosa.
La respuesta honesta es que el vibe coding funciona extraordinariamente bien para unas cosas y es una trampa para otras. El problema es que las categorías no coinciden con la intuición.
Qué es vibe coding en la práctica#
Vibe coding no es usar un asistente de IA ocasionalmente. Es un modo de trabajo donde el flujo es: describir → revisar superficialmente → aceptar → iterar. La fricción entre la idea y el código ejecutable se minimiza al máximo.
La versión extrema es la que popularizó Karpathy: "ni siquiera leo el código, solo lo ejecuto". Esa versión es útil para prototipos personales de fin de semana. Para cualquier cosa que vaya a producción necesitas una versión más matizada.
Lo que define el vibe coding productivo en un contexto profesional:
- Describes comportamiento, no implementación
- Aceptas el código si los tests pasan y el comportamiento es correcto
- No optimizas hasta que el profiler te diga que hay un problema
- Confías en el modelo para las convenciones del lenguaje y framework
- Mantienes control sobre la arquitectura y las decisiones de datos
Donde el vibe coding gana claramente#
Código de integración y glue code#
El código que conecta dos sistemas es tedioso de escribir a mano y trivial de verificar. Perfecta para vibe coding.
// Prompt: "Crea un webhook handler para Stripe que actualice el estado
// de una suscripción en Supabase cuando el pago falla o tiene éxito.
// Usa el tipo StripeWebhookEvent y valida la firma."
// Lo que genera el modelo — revisas que la lógica sea correcta,
// no que cada línea esté bien escrita
export async function POST(request: Request) {
const body = await request.text();
const signature = request.headers.get("stripe-signature");
if (!signature) {
return Response.json({ error: "No signature" }, { status: 400 });
}
let event: Stripe.Event;
try {
event = stripe.webhooks.constructEvent(
body,
signature,
process.env.STRIPE_WEBHOOK_SECRET!
);
} catch (err) {
return Response.json({ error: "Invalid signature" }, { status: 400 });
}
switch (event.type) {
case "invoice.payment_succeeded":
await supabase
.from("subscriptions")
.update({ status: "active", last_payment: new Date().toISOString() })
.eq("stripe_subscription_id", (event.data.object as Stripe.Invoice).subscription);
break;
case "invoice.payment_failed":
await supabase
.from("subscriptions")
.update({ status: "past_due" })
.eq("stripe_subscription_id", (event.data.object as Stripe.Invoice).subscription);
break;
}
return Response.json({ received: true });
}Tiempo en escribir esto a mano: 25 minutos. Tiempo en revisarlo cuando el modelo lo genera: 3 minutos. El código es verificable de un vistazo.
Tests unitarios y de integración#
Los tests son el caso de uso más subestimado del vibe coding. El modelo genera tests exhaustivos más rápido de lo que cualquier developer los escribiría, y los tests son fáciles de verificar: o pasan o fallan.
# Prompt en Claude Code
claude "Escribe tests unitarios para todas las funciones de src/lib/pricing.ts.
Cubre casos normales, edge cases (precio 0, descuentos > 100%) y errores.
Usa Vitest y sigue las convenciones de __tests__/ del proyecto"El resultado es 200 líneas de tests que habrían tardado dos horas. Los revisas en 15 minutos comprobando que los casos edge tienen sentido.
Migraciones de base de datos y scripts de mantenimiento#
Scripts que se ejecutan una vez, tienen un resultado verificable y no necesitan ser mantenidos a largo plazo.
claude "Escribe una migración SQL para normalizar el campo phone_number
en la tabla users: eliminar caracteres no numéricos, añadir prefijo +34
si el número tiene 9 dígitos sin prefijo. Incluye rollback. Hazlo seguro
para ejecutar en producción con transacción."Componentes UI sin lógica de negocio compleja#
Componentes de presentación donde el comportamiento es visual y fácilmente verificable. Formularios, tablas, cards, modales.
Donde el vibe coding falla en producción#
Lógica de negocio con invariantes implícitas#
El modelo no conoce las reglas no escritas de tu negocio. Genera código correcto según la especificación que le das, pero si esa especificación está incompleta, el código tendrá bugs que solo aparecen en producción.
// Prompt naive: "Calcula el precio final de un pedido con descuentos"
// Lo que genera el modelo — parece correcto
function calcularPrecioFinal(items, descuentos) {
const subtotal = items.reduce((sum, item) => sum + item.precio * item.cantidad, 0);
const descuento = descuentos.reduce((sum, d) => sum + d.importe, 0);
return subtotal - descuento;
}
// El bug: no sabe que en tu sistema los descuentos no pueden hacer que
// el precio baje de un mínimo por categoría, que los descuentos de
// tipo 'loyalty' se aplican después del IVA, ni que hay una regla especial
// para pedidos con artículos de proveedor X.
// Esas reglas están en la cabeza del equipo de negocio, no en el prompt.El código anterior pasará los tests básicos. Fallará en producción con pedidos reales que tocan esas invariantes.
Optimizaciones de rendimiento y queries complejas#
El modelo genera SQL que funciona. No siempre genera SQL que escala.
-- Lo que genera el modelo para "dame los usuarios más activos del último mes"
SELECT
u.id, u.email, COUNT(a.id) as total_acciones
FROM users u
LEFT JOIN actions a ON a.user_id = u.id
WHERE a.created_at >= NOW() - INTERVAL '30 days'
GROUP BY u.id, u.email
ORDER BY total_acciones DESC
LIMIT 50;
-- Parece razonable. El problema: si actions tiene 50M de filas y no hay
-- índice compuesto en (user_id, created_at), esta query bloquea la base de datos.
-- El modelo no tiene visibilidad de tu plan de ejecución real.Para queries sobre tablas grandes, el modelo debe conocer explícitamente los índices existentes, el volumen de datos y las restricciones de rendimiento. Sin ese contexto, genera código que funciona en desarrollo y explota en producción.
Seguridad y autenticación#
No porque el modelo genere código inseguro por defecto. Sino porque los bugs de seguridad suelen estar en los bordes: qué pasa cuando el token es válido pero el usuario no tiene permisos sobre ese recurso específico, qué pasa con los rate limits cuando hay múltiples instancias del servidor, qué pasa con la rotación de credenciales en sesiones activas.
Esos bordes requieren que alguien los piense explícitamente. El modelo los implementa cuando se los dices, pero no los descubre solo.
Arquitectura y decisiones de modelo de datos#
El modelo toma decisiones razonables pero no toma las tuyas. Si le pides que diseñe el esquema de base de datos para un sistema de reservas, generará algo funcional. No generará el esquema que encaja con los patrones de acceso específicos de tu caso de uso, las restricciones de tu proveedor de base de datos o la dirección en que planeas extender el sistema en doce meses.
Cómo integrar vibe coding sin perder el control#
El CLAUDE.md como contrato de convenciones#
El CLAUDE.md (o AGENTS.md) es la forma de transferir las reglas implícitas de tu proyecto al modelo. Las convenciones no escritas que cualquier developer nuevo tardará semanas en aprender.
# CLAUDE.md — Reglas de negocio críticas
## Precios y descuentos
- Los descuentos type='loyalty' se aplican DESPUÉS del IVA, no antes
- Ningún pedido puede tener precio final < precio_minimo_categoria del item con menor precio
- Los descuentos no son acumulables con promociones activas salvo que promo.stackable = true
## Base de datos
- La tabla orders tiene 8M de registros. NUNCA hagas queries sin filtro por tenant_id
- El índice compuesto en orders es (tenant_id, status, created_at) — úsalo
- users.phone_number siempre tiene formato E.164 (+34XXXXXXXXX)
## Seguridad
- Toda operación de escritura debe validar que req.user.tenantId === resource.tenantId
- Los endpoints públicos están explícitamente marcados con @Public() decorator
- Sin @Public(), el middleware de auth bloquea por defectoCon estas reglas en el CLAUDE.md, el modelo las aplica consistentemente sin que tengas que recordar incluirlas en cada prompt.
Tests antes de aceptar#
El flujo que funciona en producción no es: generar → aceptar → testear. Es: generar → hacer pasar los tests existentes → revisar si los tests existentes son suficientes → aceptar.
# Flujo con Claude Code
claude "Implementa la función calcularComision en src/lib/comisiones.ts.
Las reglas están en CLAUDE.md. Ejecuta los tests existentes cuando termines
y si no hay tests suficientes para la lógica nueva, añádelos."Si el modelo genera tests y los tests pasan, tienes un nivel razonable de confianza. Si hay lógica de negocio nueva sin tests, ese es el momento de revisar a fondo, no después.
Code review enfocado en invariantes#
Cuando revisas código generado por IA, el tiempo no debe gastarse en verificar que el for loop está bien escrito. Debe gastarse en verificar que las invariantes de negocio están respetadas y que los edge cases están cubiertos.
Preguntas concretas en un code review de código generado:
- ¿Qué pasa si este argumento es null o undefined?
- ¿Esta operación es atómica o puede quedar en estado intermedio?
- ¿Este código escala cuando hay 100x más datos?
- ¿Hay alguna regla de negocio implícita que el código no respeta?
El error conceptual más común#
El vibe coding no es delegar la programación. Es cambiar qué parte del trabajo hace el programador.
Antes: el programador escribía código.
Con vibe coding: el programador define comportamiento, verifica corrección y toma decisiones de arquitectura.
El valor del developer no desaparece. Se desplaza. El que lleva años en un sistema sabe las invariantes implícitas, conoce los casos edge que han quemado al equipo y entiende por qué ciertas decisiones se tomaron así. Ese conocimiento es imposible de transferir a un modelo sin documentarlo explícitamente. El developer que lo documenta bien multiplica su impacto. El que no lo documenta y acepta código sin revisar acumula deuda que aparece en producción.
Errores comunes al implementar vibe coding en equipos#
Vibe coding sin tests. Sin tests, no tienes forma de saber si el código generado es correcto más allá de probarlo manualmente. Los tests son lo que convierte "parece que funciona" en "funciona".
Aceptar código sin leer en lógica de negocio. Para integraciones y glue code, revisar superficialmente es suficiente. Para reglas de negocio, los bugs están en los detalles. Lee el código que toca lógica de negocio.
CLAUDE.md vacío o desactualizado. Si el CLAUDE.md no tiene las reglas de negocio críticas, el modelo no puede aplicarlas. Es responsabilidad del equipo mantenerlo actualizado con cada decisión que no es obvia.
Usar vibe coding para optimizaciones de rendimiento. El modelo no tiene visibilidad de tu plan de ejecución real, tus índices o los patrones de acceso de producción. Para optimizaciones, dale contexto explícito o hazlo a mano.
No versionar el CLAUDE.md. El CLAUDE.md debe estar en el repositorio como cualquier otro archivo de configuración. Si solo está en local, los demás miembros del equipo generan código sin las reglas que tú tienes documentadas.
Conclusión#
El vibe coding es una herramienta genuinamente útil para developers que saben cuándo usarla. Código de integración, tests, scripts de mantenimiento y componentes de presentación son casos donde la velocidad es enorme y el riesgo es bajo. Lógica de negocio compleja, optimizaciones de rendimiento y decisiones de arquitectura requieren más control, más contexto transferido al modelo y más revisión.
El developer que aprende a mover la fricción al lugar correcto del flujo de trabajo, que documenta las invariantes implícitas en el CLAUDE.md y que revisa con criterio en lugar de en detalle, multiplica su productividad sin sacrificar la calidad. El que adopta el vibe coding sin criterio acaba con una base de código que "funciona" hasta que deja de funcionar por razones que nadie entiende.
La diferencia entre los dos está en el nivel de control que mantienes sobre el sistema, no en cuántas líneas escribe el modelo.
Más sobre IA & Automación
Ver todos →