Mi stack actual
Actualmente uso TypeScript y Bun como base para la mayoría de mis proyectos. Para aplicaciones web suelo elegir React con Vite, React Router y TanStack Query. Construyo la UI con Tailwind CSS, shadcn/ui y Radix UI.
En el backend uso Hono y Zod. Cuando necesito persistencia, mi primera opción es PostgreSQL con Drizzle. Para autenticación estoy usando Better Auth. Normalmente despliego el frontend en Cloudflare Pages y la API en Railway.
TypeScript en casi todo
TypeScript es la parte más estable de mi stack. Lo uso en aplicaciones web, APIs, scripts, proyectos móviles e interfaces de terminal.
Esto se nota más cuando la lógica deja de ser simple. En una aplicación móvil, por ejemplo, las reglas del juego viven en un motor escrito en TypeScript puro. React Native no decide quién muere, quién vota o cuándo termina una partida. La interfaz envía comandos y el motor devuelve un nuevo estado con sus eventos. Puedo probar esas reglas sin abrir la aplicación.
Bun para el trabajo diario
Uso Bun para instalar dependencias, ejecutar scripts y correr pruebas. También lo uso como runtime para APIs.
Me gusta porque reduce bastante el tiempo que paso esperando comandos, pero no intento forzar toda la estructura del repositorio alrededor de él. En uno de mis monorepos, las aplicaciones conservan dependencias y lockfiles independientes. El package raíz coordina los comandos, mientras la API, el CLI y la web mantienen sus propios ciclos de instalación y deploy.
La raíz me sirve para ejecutar el proyecto completo. Cada aplicación sigue pudiendo vivir por su cuenta.
React para aplicaciones web
Mi punto de partida en frontend es React con Vite. React Router se ocupa de las rutas y TanStack Query de los datos que vienen del servidor.
He usado stores globales muchas veces, pero ya no empiezo uno por costumbre. Si un dato pertenece al servidor, prefiero que TanStack Query maneje su carga, caché e invalidación. Zustand aparece cuando sí existe estado compartido que pertenece a la interfaz.
Para estilos uso Tailwind CSS. shadcn/ui y Radix UI me dan una buena base para componentes interactivos sin encerrarme en la apariencia de una librería. Normalmente termino modificando esos componentes dentro del proyecto, que es precisamente lo que me interesa de shadcn/ui.
Después añado piezas más específicas cuando hacen falta: Sonner para notificaciones toast, cmdk para una paleta de comandos o Vaul para un drawer. No instalo todas desde el inicio.
Hono para las APIs
Después de trabajar con distintos frameworks de backend, Hono se convirtió en la opción que pruebo primero.
Uso Zod en los límites de la aplicación. Valido las entradas HTTP, la configuración y las respuestas externas que no controlo. Esto último es especialmente importante en una API que consulta varios proveedores: cada uno devuelve datos diferentes y cualquiera puede cambiar su respuesta o dejar de funcionar.
Cuando el frontend y la API se despliegan por separado, genero un documento OpenAPI desde las rutas de Hono. Orval usa ese documento para crear los clientes del frontend. Prefiero eso a escribir una función con fetch y luego mantener sus tipos manualmente en otro lugar.
No siempre necesito OpenAPI. En un monorepo uso Hono RPC porque todas las aplicaciones pueden obtener los tipos directamente de AppType. La elección depende de qué tan independientes quiero que sean los consumidores de la API.
PostgreSQL y Drizzle
Cuando necesito una base de datos, casi siempre empiezo con PostgreSQL. Drizzle se encarga del esquema y las consultas, Drizzle Kit de las migraciones y postgres.js de la conexión.
Antes usaba Prisma. No tengo una gran historia sobre por qué cambié. Probé Drizzle en un proyecto, seguí usándolo en el siguiente y con el tiempo se volvió mi primera opción. Me gusta que el esquema y las consultas se sientan cerca de SQL, pero el cambio fue gradual, no una decisión tomada en un solo día.
Para autenticación estoy usando Better Auth. Lo conecto a Drizzle y ya lo he usado con organizaciones y passkeys.
Tampoco todos los proyectos necesitan esta parte del stack. Una API que solo consulta proveedores y normaliza sus respuestas puede funcionar sin base de datos. Una aplicación móvil offline-first puede guardar sus datos en SQLite y funcionar sin backend. Añadir PostgreSQL resolvería un problema que ninguno de los dos tiene.
Pruebas
Vitest es mi opción habitual para frontend y backend. En React lo uso con Testing Library y jsdom. Para la API prefiero probar servicios y endpoints completos cuando el costo sigue siendo razonable.
Si una prueba depende del comportamiento real de PostgreSQL, uso PGlite. Me permite cubrir consultas, restricciones y transacciones sin reemplazar la base de datos por mocks que se comportan de otra manera.
Algunos de mis proyectos usan el runner de Bun. No me preocupa que todos los repos tengan exactamente la misma herramienta. Me importa más poder probar la lógica sin montar media aplicación para llegar a ella.
Deploy
Suelo desplegar el frontend en Cloudflare Pages y la API en Railway. PostgreSQL también corre como un servicio administrado en Railway.
Mantengo el frontend y el backend separados porque quiero desplegarlos de forma independiente. Comparten un contrato generado, no un proceso de deploy. Railway construye la API con Bun mediante Railpack, así que por ahora no necesito mantener un Dockerfile.
Una API sin base de datos encaja mejor en Cloudflare Workers cuando depende de cachés de Cloudflare.
Cuando el proyecto pide otra cosa
No quiero que cada proyecto nuevo repita exactamente esta combinación.
En una aplicación móvil offline-first uso Expo, React Native, SQLite y Reanimated. Las partidas deben continuar aunque no exista conexión, así que el estado importante vive en el dispositivo. En ese proyecto no uso Tailwind CSS, TanStack Query, Hono ni Better Auth.
También hice una web con SolidJS y SolidStart porque quería probar SolidJS en algo pequeño. Me gustó trabajar con él, pero por ahora React sigue siendo la opción con la que empezaría una aplicación web.
En otro proyecto uso Astro para el sitio público y React con Vite para el panel administrativo. También es donde Hono RPC tiene más sentido que OpenAPI. Son decisiones que nacen de cómo están relacionadas las aplicaciones, no de una regla que quiera aplicar en todas partes.
Algunas exploraciones se quedan en un solo proyecto. Otras empiezan así y terminan formando parte de lo que uso siempre. Drizzle pasó por ese recorrido. SolidJS todavía no.
Ahora mismo empezaría una aplicación web con esta base y quitaría piezas antes de añadir otras. No necesito que todos mis proyectos usen las mismas herramientas. Me basta con tener un punto de partida que conozco bien y poder cambiarlo cuando el producto lo justifica.