v0 → una aplicación, no una pila de componentes

v0 te dio una UI hermosa.
Nunca te prometió una aplicación.

v0 es honesto con su alcance: genera componentes, no sistemas — sin API routes, sin capa de datos, sin auth. El spaghetti arranca cuando promovés esos mockups a producto y la lógica de servidor aterriza donde entra — adentro de componentes, en server actions improvisadas, en el archivo que estaba abierto. useDeploy es la otra mitad: un backend tipado y testeado que le da a cada pieza de lógica una dirección, para que tu front de v0 quede tan limpio como el día que se generó.

Dónde se tuercen de verdad los proyectos de v0

El output de v0 es genuinamente bueno — los devs describen consistentemente los componentes como limpios y bien estructurados. La trampa es la mitad que falta: v0 genera componentes de UI, no aplicaciones completas — sin API routes, sin queries a la base, sin lógica de autenticación. Así que cuando el mockup tiene que volverse producto, esa lógica se escribe en algún lado — y sin una arquitectura de backend que la reciba, "algún lado" significa adentro de los propios componentes: un fetch acá, un chequeo de permisos allá, matemática de precios en un click handler. Iterar lo empeora: las ediciones manuales se pisan con las generaciones siguientes, y componentes que andan contra el preview de v0 se rompen al conectarse a datos reales. El resultado no son componentes desprolijos. Es un frente hermoso atornillado a una app sin espalda — y cada prompt desparrama la lógica portante cada vez más finita entre archivos diseñados para renderizar, no para decidir.

Síntomas de un mockup de v0 promovido demasiado rápido

Componentes de display tomando decisiones de negocio

Matemática de precios, chequeos de permisos y fetches inline en lo que v0 diseñó como componente presentacional. Renderiza hermoso y decide peligroso.

Cada página fetchea a su manera

Una pantalla usa una server action, otra un route handler, una tercera habla directo con la base. Tres caminos de datos, cero validación compartida.

Auth como prop drilleada por el árbol

Sin capa de sesión — solo objetos user pasados hacia abajo y chequeados ad hoc, distinto, en cada página que se acordó de hacerlo.

La regeneración se come tu cableado

Re-prompteás un componente en v0 y la lógica que le cableaste a mano desaparece con el markup viejo — un dolor conocido de iterar in place.

Verde en preview, rojo en producción

Todo anda contra los datos de preview de v0, y se rompe con payloads reales — porque nada entre UI y API valida qué forma tienen los datos de verdad.

La pared: un gate de CI que atrapa el payload drift

El typecheck solo no puede salvar un codebase UI-first — tus componentes pueden estar perfectamente tipados contra un payload que el server nunca manda. useDeploy comparte schemas Zod vía @app/contracts, genera los tipos del cliente desde el schema OpenAPI del server, y hace fallar CI cuando driftean. Atrapa el payload drift, no solo el type drift: la clase exacta de bug donde el form compila limpio y el usuario recibe un 400.

CI: api-types-fresh
 1  Running CI checks for PR #218…
 2  
 3    ✓ typecheck                    passed
 4    ✓ unit + integration (450+)    passed
 5    ✗ api-types-fresh              FAILED
 6  
 7    apps/client/lib/api/openapi-types.ts is stale.
 8  
 9      client sends:    { fullName: string }
10      server expects:  { name: string }
11  
12    Run `bun run generate:api` and commit the diff.
13    Merge blocked until server and client agree.

La mitad de atrás, ya construida

Una API real para que llamen tus componentes

Seis bounded contexts — iam, tenancy, billing, storage, ai, webhooks — exponen endpoints HTTP tipados que tu UI consume vía openapi-fetch. Ningún componente vuelve a improvisar acceso a datos.

Una dirección por regla de negocio

Cada módulo se parte en capas de domain, application, infrastructure e interface. Los límites de plan viven en el domain de billing — un solo lugar, custodiado por lint, cubierto por tests.

Fronteras que el build defiende

El flat-config de ESLint prohíbe imports de express y @prisma/client en código de domain. El layering sobrevive a cada generación futura porque las violaciones fallan CI, no el code review.

Payload drift atrapado en CI

El gate api-types-fresh regenera los tipos del cliente desde el schema OpenAPI del server y falla el PR si difieren — atrapando el drift que el typecheck solo no ve.

450+ tests, gate E2E, outbox durable

Una suite de regresión y checks end-to-end de Playwright gatean cada merge, y los side effects fluyen por un event bus con outbox en vez de esconderse en handlers.

El camino de migración: v0 se queda, la improvisación se va

Mantené a v0 en el loop — está haciendo su trabajo. La migración es darle a su output una estructura receptora de verdad. Soltá tus componentes en el cliente Next.js de useDeploy; el markup React + Tailwind se transfiere tal cual. Después recableá, pantalla por pantalla: sacá los fetches inline y las server actions improvisadas, y reemplazalos por llamadas vía el cliente openapi-fetch tipado, cuyos schemas vienen de @app/contracts — las mismas definiciones Zod contra las que valida el server. Las decisiones de negocio que esos componentes cargaban se mudan a use cases adentro del módulo correcto: límites de plan a billing, invitaciones a tenancy, uploads a storage. De ahí en adelante, regenerá UI en v0 todo lo que quieras. El problema del overwrite deja de ser peligroso, porque los componentes ya no cargan lógica — y el gate api-types-fresh garantiza que una pantalla regenerada o compila contra la API real o falla en CI, nunca en silencio en producción.

Preguntas sobre v0, respondidas

¿v0 es el problema?+
No — de los AI builders, v0 es el más honesto con su alcance. Genera UI, y las reseñas de sentimiento de devs encuentran esa UI consistentemente bien estructurada. El spaghetti viene de lo que pasa después: promover componentes a app sin una arquitectura de backend que reciba la lógica.
¿Los componentes de v0 andan con el front-end de useDeploy?+
Sí. v0 emite React con Tailwind, y el cliente de useDeploy es una app Next.js — el markup entra directo. El cambio está en el cableado: los fetches inline y las server actions improvisadas se reemplazan por llamadas vía el cliente openapi-fetch tipado, así cada payload que consume el componente está chequeado por contrato.
¿Qué pasa con las server actions que ya escribí?+
Su lógica consigue una dirección. Lo que sea que hacía una server action — chequear un límite de plan, escribir un registro, llamar a un provider — se muda a un use case adentro del módulo correspondiente, detrás de su port. La UI se queda con una llamada finita; la decisión de negocio por fin vive donde lint y tests la defienden.
¿Puedo seguir iterando en v0 después de la migración?+
Con total libertad — este setup está armado para ese workflow. Regenerá pantallas cuanto quieras; como el acceso a datos pasa por @app/contracts y el gate api-types-fresh, un componente regenerado o compila contra la API real o falla visible en CI. El problema del overwrite deja de costarte lógica, porque la lógica ya no vive en el componente.

Una licencia. Dos formas de tenerla.

CORE

Founder

$99pago único

Un snapshot congelado de UseDeploy. Tuyo para siempre, sin updates.

  • Descarga del zip con versión frozen
  • Código completo, uso comercial, proyectos ilimitados
  • Los 800+ tests · todas las páginas de docs
  • Refund a 14 días
RECOMMENDED

LATEST + UPDATES

Lifetime

$199$249pago único

Siempre el último UseDeploy. Re-descargá cada release, gratis.

  • Zip de la última versión — re-descargable para siempre
  • Cada release futuro sin cargo extra
  • Soporte Discord priority
  • Los 800+ tests · todas las páginas de docs
  • Refund a 14 días

Tu UI se merece un backend que le siga el ritmo

Soltá tus componentes de v0 en un cliente Next.js cableado a una API tipada y testeada — seis bounded contexts, gates de contrato en CI y una dirección para cada pieza de lógica.