Serie: Vibe Coding a tu manera — Post 1 de 2
Avance del Post 2: "De localhost a producción: cómo publicar tu app de vibe coding en un servidor web en la nube"
Opciones alternativas de titular:
- Construye tu propio Lovable: un entorno de vibe coding gratuito y local para Mac
- Vibe coding sin suscripción: VSCode + Cline + Ollama + Supabase
¿Qué es eso del vibe coding?
El vibe coding es una forma de construir software en la que describes lo que quieres en lenguaje natural y una IA escribe el código — mientras tú diriges, revisas y reaccionas a lo que aparece en pantalla. Tú sigues al volante como persona de producto: "añade un interruptor de modo oscuro", "el botón de borrar debería pedir confirmación", "haz que la lista se ordene por fecha". La IA se encarga de la sintaxis, la estructura de archivos, el código repetitivo. Tú te encargas del vibe: qué debe hacer la app y qué sensación debe transmitir.
El término despegó a principios de 2025 (acuñado por el investigador de IA Andrej Karpathy), y caló porque describe algo real: para una clase enorme de aplicaciones — herramientas internas, prototipos, proyectos personales, productos pequeños — ya no necesitas escribir la mayor parte del código tú mismo. Necesitas ser capaz de dirigir el código que se está escribiendo, y de reconocer cuándo algo no cuadra.
¿Qué es Lovable?
Lovable es una de las plataformas de vibe coding más populares. Escribes lo que quieres en un cuadro de chat y construye una aplicación web funcional delante de ti — interfaz de usuario, base de datos, login, subida de archivos, todo — con una vista previa en vivo que se actualiza mientras conversas. Por debajo, Lovable genera un stack web moderno bastante estándar: React con TypeScript, estilizado con Tailwind CSS y componentes de shadcn/ui, respaldado por Supabase (una base de datos Postgres con autenticación y almacenamiento de archivos integrados).
Es un gran producto. También es una suscripción con créditos por uso, tu código vive en su nube y las llamadas de IA van a modelos comerciales. Lo cual plantea una pregunta obvia para los que disfrutan trastear:
¿Puedes montar la misma experiencia por tu cuenta — gratis, local y privada?
Sí. De eso trata este post.
El objetivo de este post
Al terminar, tendrás un entorno de vibe coding completo funcionando en tu Mac:
| Lo que te da Lovable | Tu equivalente local y gratuito |
|---|---|
| Cuadro de chat que construye la app | Cline (un agente de programación con IA dentro de VSCode) |
| El cerebro de IA | Ollama ejecutando un modelo open source en local |
| Vista previa en vivo | Servidor de desarrollo de Vite en tu navegador, con hot reload en cada cambio |
| Código oculto | VSCode — el mismo código, salvo que puedes verlo y tocarlo |
| Base de datos, auth, almacenamiento | Supabase corriendo en local en contenedores — exactamente la misma tecnología que Lovable usa en la nube |
| Publicación con un clic | Llega en el Post 2 de esta serie |
Coste total: 0 €. Tu código nunca sale de tu máquina. Tus prompts nunca salen de tu máquina. Y como es el mismo stack que usa Lovable, todo lo que construyas tiene un camino limpio hacia un hosting real en la nube más adelante.
Una advertencia honesta antes de empezar: un modelo open source local en hardware de consumo no es tan capaz como los modelos de frontera que Lovable alquila. Tu agente local hará de vez en cuando alguna tontería, y este post te muestra las barreras de protección que mantienen eso bajo control (son la mitad del valor del artículo — me topé de verdad con cada una de las trampas de abajo durante la configuración).
Qué necesitas antes de empezar
- Un Mac (Apple Silicon recomendado; con 16 GB de RAM vas cómodo, con 8 GB funciona usando los trucos de la sección sobre RAM más abajo)
- VSCode instalado, con la extensión Cline
- Ollama instalado, con un modelo de programación descargado —
qwen2.5-coder(7b o 14b) es actualmente una de las opciones más potentes que caben en hardware de consumo
La configuración de VSCode + Cline + Ollama está bien cubierta en otros sitios; este post empieza donde la mayoría de las guías se detienen: el servidor de pruebas local y la base de datos — la parte que convierte "una IA que edita archivos" en "una experiencia tipo Lovable con una app real en ejecución".
Fase 1: configuración única de la máquina (~20 minutos)
Cuatro herramientas de línea de comandos, instaladas una sola vez, usadas por todos tus proyectos futuros. Abre la Terminal (en VSCode: Terminal → New Terminal).
1. Homebrew — el gestor de paquetes del Mac
Comprueba si ya lo tienes:
brew --versionSi eso imprime una versión, sigue adelante. Si no:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"En Apple Silicon, ejecuta los dos comandos extra que el instalador imprime al final (añaden brew a tu PATH) y luego abre una terminal nueva.
2. OrbStack — el runtime de contenedores
Tu base de datos local correrá en contenedores. La herramienta habitual es Docker Desktop, pero OrbStack es un reemplazo directo que consume notablemente menos RAM y batería — y la RAM importa, porque Ollama ya se está comiendo buena parte de ella.
brew install orbstack
open -a OrbStackAcepta los avisos; después vive discretamente en tu barra de menús. Verifica:
docker --version3. Node.js — ejecuta el servidor de desarrollo
brew install node
node -vTrampa #1 — mensajes de instalación que asustan. Homebrew puede imprimir "Caveats" como "Single Executable Application is disabled" o "Temporal support is disabled." Parecen errores; son avisos inofensivos sobre funciones de nicho de Node que nada en este stack utiliza. Si ves la jarra de cerveza 🍺, la instalación fue un éxito.
4. Supabase CLI — todo tu backend en una sola herramienta
brew install supabase
supabase --versionEsta es la pieza que la mayoría de las guías pasa por alto. La CLI de Supabase ejecuta un backend local completo — base de datos Postgres, autenticación, almacenamiento de archivos y una interfaz de administración visual — con un solo comando. Es el mismo software open source que hay detrás del backend en la nube de Lovable. Nunca instalas ni configuras Postgres tú mismo.
Fase 2: crear un proyecto (~20 minutos, una vez por proyecto)
5. Generar el esqueleto de la app
Elige una carpeta donde vivirán todos tus proyectos, y cíñete a ella religiosamente:
mkdir -p ~/Projects && cd ~/Projects
npm create vite@latest my-first-app -- --template react-ts
cd my-first-app
npm installEl generador pregunta "Which linter to use?" — elige ESLint. Es el estándar establecido desde hace mucho, y (un tema que verás a lo largo de todo el post) los modelos de IA locales han visto muchísimos más proyectos con ESLint durante su entrenamiento que con alternativas más nuevas, así que cometen menos errores con él.
Abre el proyecto en VSCode con code . — y si la terminal dice command not found: code, es un ajuste de VSCode que se hace una sola vez: pulsa Cmd+Shift+P, escribe "shell command", selecciona "Shell Command: Install 'code' command in PATH" y abre una terminal nueva.
Trampa #2 — la trampa de la carpeta equivocada. Esto me costó más tiempo que cualquier otra cosa en toda la configuración. Si abres VSCode mientras tu terminal está situada en otro directorio, tus ediciones van a parar a el proyecto equivocado — y comandos posteriores fallan misteriosamente porque los archivos que esperan nunca fueron modificados. Dos hábitos lo evitan por completo: antes de cualquier comando, echa un vistazo al prompt de la terminal o ejecuta pwd — debe terminar en el nombre de tu proyecto; y en VSCode usa File → Open Folder para abrir exactamente la carpeta del proyecto, nada por encima de ella.Ahora verifica el corazón de la configuración — tu servidor de pruebas local:
npm run devAbre http://localhost:5173 — la página inicial carga. Este servidor de Vite hace hot reload del navegador en menos de un segundo tras cualquier cambio de archivo, que es lo que crea esa sensación de Lovable de "verlo construirse en vivo". Déjalo corriendo en su propia pestaña de terminal; abre pestañas nuevas (el icono +) para otros comandos.
Trampa #3 — ¿puerto 5174? Si la URL muestra alguna vez 5174 en lugar de 5173, tienes un segundo servidor de desarrollo corriendo en una pestaña de terminal olvidada. No es dañino, pero sí confuso. Cierra los duplicados; ejecuta exactamente uno.
6. Tailwind CSS + shadcn/ui — el lenguaje visual de Lovable
npm install tailwindcss @tailwindcss/vite(Si npm avisa sobre fsevents y "install scripts not yet covered by allowScripts" — es una función de seguridad reciente de npm. fsevents es un ayudante de confianza para la observación de archivos en macOS; apruébalo con npm approve-scripts fsevents o simplemente sigue adelante, todo funciona de las dos maneras.)
Reemplaza todo el contenido de src/index.css por una sola línea:
@import "tailwindcss";Trampa #4 — pegar reemplaza, no añade. Cuando una guía dice "reemplaza el contenido del archivo", selecciona todo (Cmd+A), borra y después pega. Yo me las arreglé para pegar unvite.config.tsnuevo debajo del antiguo, produciendo un archivo con imports duplicados y dos default exports — rotura instantánea. Si algo da error justo después de una edición, comprueba que no tienes el contenido del archivo dos veces.
Ahora, antes de ejecutar el instalador de shadcn, haz la configuración que este exige en silencio. Este es el paso donde mi configuración falló de verdad por primera vez:
Trampa #5 — shadcn necesita un "import alias" que Vite no trae de serie. shadcn/ui escribe componentes que importan desde@/components/...— donde@es un atajo hacia tu carpetasrc. La plantilla de Vite no define ese atajo, así quenpx shadcn initfalla en sus comprobaciones previas con "Could not find valid path aliases." La solución son tres pequeñas ediciones, hechas una vez por proyecto:
Instala el ayudante de tipos:
npm install -D @types/nodeReemplaza vite.config.ts por:
import path from "path"
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [react(), tailwindcss()],
resolve: {
alias: { "@": path.resolve(__dirname, "./src") },
},
})Reemplaza tsconfig.json por:
{
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
],
"compilerOptions": {
"baseUrl": ".",
"paths": { "@/*": ["./src/*"] }
}
}Y en tsconfig.app.json, añade estas dos líneas al principio del bloque "compilerOptions" existente:
"baseUrl": ".",
"paths": { "@/*": ["./src/*"] },Ahora shadcn sí pasará sus comprobaciones:
npx shadcn@latest init
npx shadcn@latest add button card inputEl init hace dos preguntas que las guías actuales rara vez mencionan. "Select a component library?" — elige Radix UI, aunque la herramienta recomiende Base UI. Radix es sobre lo que shadcn se construyó originalmente y lo que usa Lovable, lo que de nuevo significa que es lo que tus modelos locales conocen mejor. "Which preset?" — Nova (iconos Lucide, el look clásico de shadcn). Valores por defecto para todo lo demás.
7. Arranca tu backend local + base de datos
supabase init
supabase startEl primer supabase start descarga alrededor de una docena de imágenes de contenedor — dale unos minutos.
Trampa #6 — una descarga falla aleatoriamente. Una de mis trece imágenes (storage-api) falló al descargarse con un error críptico del registry mientras las otras doce se completaban con éxito. No había nada mal en mi configuración — los registries de contenedores tienen hipos de vez en cuando. La solución es anticlimática: ejecutasupabase startotra vez. Retoma el proceso y descarga solo lo que falta.
Cuando termine, ejecuta supabase status para ver lo que ahora tienes:
| Servicio | Dirección |
|---|---|
| Tu app (servidor de pruebas) | http://localhost:5173 |
| Studio — administración visual de la base de datos | http://127.0.0.1:54323 |
| API (REST/Auth/Storage) | http://127.0.0.1:54321 |
| Postgres, conexión directa | puerto 54322 |
Abre Studio en tu navegador y echa un vistazo: editor de tablas, consola SQL, usuarios de auth, buckets de almacenamiento. Esta es tu ventana a la base de datos durante todo el flujo de vibe coding — cuando la IA afirme que guardó algo, Studio es donde compruebas que de verdad lo hizo.
(Puede que también veas "Stopped services: imgproxy, pooler" — son componentes opcionales; es normal.)
8. Conecta la app con la base de datos
npm install @supabase/supabase-jsTrampa #7 — las claves no se parecen a lo que dicen los tutoriales. La mayoría de las guías te dicen que copies una "anon key" con pinta deeyJhbGci.... Las versiones más recientes de Supabase reemplazaron ese formato:supabase statusahora imprime una clave Publishable (sb_publishable_...) y una clave Secret (sb_secret_...). La clave Publishable es la clave de tu app. La clave Secret es la clave de administrador — jamás se acerca al código del frontend.
Crea un archivo llamado .env.local en la raíz del proyecto:
VITE_SUPABASE_URL=http://127.0.0.1:54321
VITE_SUPABASE_ANON_KEY=sb_publishable_...your-key-here...Y el cliente en src/lib/supabase.ts:
import { createClient } from '@supabase/supabase-js'
export const supabase = createClient(
import.meta.env.VITE_SUPABASE_URL,
import.meta.env.VITE_SUPABASE_ANON_KEY
)9. El archivo .clinerules — el paso más infravalorado
Crea un archivo llamado .clinerules en la raíz del proyecto. Cline lo lee automáticamente antes de cada tarea, y es la diferencia entre un agente que sigue tu arquitectura y uno que improvisa:
# Project rules
## Stack
- React + TypeScript + Vite
- Tailwind CSS v4 + shadcn/ui (components live in src/components/ui)
- Supabase for database, auth, and storage (client in src/lib/supabase.ts)
## Rules
- Use existing shadcn/ui components before writing custom ones.
- Never hand-write authentication logic; always use supabase.auth methods.
- All database schema changes go into SQL migration files via
`supabase migration new <name>` — never apply schema changes directly.
- After schema changes, apply with `supabase db reset`.
- Read environment variables only via import.meta.env.VITE_*.
- Keep components small; one component per file.
- Do not add new dependencies without asking first.Los modelos de frontera suelen inferir estas convenciones; los modelos locales pequeños necesitan tenerlas por escrito. Verás exactamente por qué en un momento.
10. Control de versiones — tu botón de deshacer para los errores de la IA
git init
git add -A
git status # check the list: .env.local must NOT appear (your keys stay out of git)
git commit -m "Project scaffold: Vite + React + Tailwind + shadcn + Supabase"Cuando una IA edita tu código, git es tu red de seguridad: haz commit después de cada funcionalidad que funcione, y cualquier estropicio provocado por la IA está a un git checkout -- . de quedar deshecho.
Trampa #8 — archivos temporales de Supabase inflando tus commits. Después de tu primer commit de funcionalidad puede que veas miles de líneas insertadas provenientes desupabase/.temp/...— archivos de trabajo internos que no pertenecen al control de versiones. Exclúyelos una sola vez:echo "supabase/.temp/" >> .gitignore, luegogit rm -r --cached supabase/.tempy haz commit.
Fase 3: la primera funcionalidad — y lo que los agentes de IA hacen mal con las bases de datos
Configuración lista. Hora de hacer vibe coding. Con supabase start y npm run dev corriendo los dos, abre el panel de Cline y escribe este prompt:
Create a todos feature: a migration for a `todos` table (id uuid pk default gen_random_uuid(), title text not null, done boolean default false, created_at timestamptz default now()), then a page using shadcn/ui components that lists, adds, and toggles todos via the supabase client.
(Los prompts a la IA funcionan mejor en inglés, así que aquí lo dejamos tal cual.)
Cline propondrá cambios en archivos, tú los apruebas, y el navegador hace hot reload hacia una interfaz de todos. Mágico — hasta que intentas añadir un todo. Aquí viene la parte honesta que la mayoría de los tutoriales se salta. Mi primera funcionalidad falló dos veces, de dos formas instructivas:
Trampa #9 — "Could not find the table 'public.todos'". La interfaz existe pero la tabla de la base de datos no. Las bases de datos cambian mediante archivos de migración — pequeños scripts SQL ensupabase/migrations/que se aplican consupabase db reset. Mi modelo local construyó la interfaz pero se saltó la migración (sí, a pesar del archivo de reglas — los modelos pequeños a veces lo hacen). El hábito que atrapa esto siempre: después de cualquier funcionalidad que toque datos, comprueba que apareció un nuevo archivo.sqlensupabase/migrations/. Si no, dile a Cline: "Put the schema changes in a migration file viasupabase migration new." Después aplica consupabase db reset.
Trampa #10 — "permission denied for table todos". Progreso — la tabla ya existe — pero Postgres le niega a tu app el acceso a ella. Las apps de Supabase hablan con la base de datos como un rol restringido "anon", y las tablas nuevas necesitan permisos de acceso explícitos más una política de Row Level Security. La solución robusta es una migración que gestione la creación y los permisos juntos. Crea una con supabase migration new create_todos y dale esta forma:create table if not exists public.todos (
id uuid primary key default gen_random_uuid(),
title text not null,
done boolean not null default false,
created_at timestamptz not null default now()
);
grant usage on schema public to anon, authenticated;
grant select, insert, update, delete on table public.todos to anon, authenticated;
alter table public.todos enable row level security;
drop policy if exists "dev allow all" on public.todos;
create policy "dev allow all" on public.todos
for all using (true) with check (true);Después supabase db reset, refresca el navegador — y funciona. Añade un todo, recarga la página, persiste. Abre Studio y ahí está tu fila en Postgres. Esa es la cadena completa, verificada: tu prompt → IA local → código + migración → base de datos real → interfaz en vivo.
(Esa política de "allow all" está deliberadamente abierta de par en par — correcta para el desarrollo local, donde el único usuario eres tú, y exactamente lo que se reemplaza por reglas de seguridad reales antes de que nada salga a producción. Ese es un tema del Post 2.)
Trampa #11 — migraciones duplicadas. Después del arreglo, mi agente creó tardíamente su propia migración de creación de tabla, lo que habría hecho estallar el siguientesupabase db reset(crear una tabla que ya existe es un error). Si dos migraciones crean la misma tabla, borra la redundante y vuelve a ejecutarsupabase db resetpara demostrar que el conjunto está sano.
Haz commit del hito: git add -A && git commit -m "Add todos feature".
Cómo es realmente el vibe coding del día a día
Una fuente de confusión que conviene aclarar: VSCode trae su propio panel de chat con IA, y Cline añade un segundo. No tienen ninguna relación. Usa solo el panel de Cline — es el que está conectado a Ollama y el que puede editar archivos y ejecutar comandos. Oculta el chat integrado y no vuelvas a pensar en él.
El mapeo con Lovable, una pantalla, dos mitades: VSCode con el panel de Cline a la izquierda, navegador con tu app a la derecha. El chat de Lovable = Cline. La vista previa de Lovable = localhost:5173. El código oculto de Lovable = visible en tu editor, lo cual es una ventaja, no un defecto.
El ritmo diario:
# session start
supabase start
npm run devLuego, el bucle: describe una funcionalidad a Cline → revisa los diffs → aprueba → mira cómo el navegador hace hot reload → si había datos de por medio, echa un vistazo a supabase/migrations en busca de un archivo nuevo → pruébala → git add -A && git commit -m "feature". Cuando algo se tuerza, díselo a Cline o haz rollback con git. Al terminar la sesión, supabase stop — lo que nos lleva al hardware.
Una nota sobre la RAM (dueños de un MacBook Air, esto es para ti). Ollama con un modelo 7b quiere 5–8 GB; el stack local de Supabase ocupa 1.5–2.5 GB; Vite y tu navegador, otros 1–2 GB. Con 16 GB todo coexiste felizmente. Con 8 GB, usa el truco del interruptor: supabase stop mientras el modelo está en plena generación pesada, supabase start cuando quieras probar. Y tres hábitos que ayudan específicamente a los modelos locales pequeños: mantén las tareas pequeñas (una funcionalidad por conversación de Cline, y luego empieza una tarea nueva — los chats largos degradan a los modelos pequeños), usa el Plan mode de Cline antes del Act mode para cualquier cosa no trivial, y mantén tu .clinerules al día a medida que el proyecto crece.
Lo que tienes ahora — y lo que viene después
Por el precio de una tarde y cero euros al mes, ahora ejecutas el mismo stack que Lovable vende: un agente de IA construyendo una app con React + Tailwind + shadcn contra una base de datos Postgres real, vista previa en vivo incluida, enteramente en tu propia máquina. Más tres cosas que Lovable no te da: privacidad total, código visible que de verdad posees y entiendes, y barreras de protección (git, migraciones, archivo de reglas) que usan los desarrolladores profesionales.
Todo lo hecho hasta ahora vive en localhost — visible solo para ti. El Post 2 de esta serie cubre el capítulo que falta: publicar. Cómo poner en producción una app construida con vibe coding en un servidor web real en la nube — GitHub para el código, Vercel para el frontend, Supabase Cloud para la base de datos — donde toda la transición de local a producción se reduce a cambiar dos variables de entorno y ejecutar dos comandos. Y, algo crítico, cómo reemplazar esa política de seguridad de desarrollo abierta de par en par por reglas reales de Row Level Security antes de que tu app se encuentre con el internet público.
Hasta entonces: supabase start, npm run dev, y ponte a construir algo.
Este es el Post 1 de la serie "Vibe Coding a tu manera". Post 2: "De localhost a producción: cómo publicar tu app de vibe coding en un servidor web en la nube".