🔌 Backend & APIs 🗄️ Datos & Bases de Datos

Bun.sql y los nuevos drivers nativos: bases de datos sin ORM pesado

Bun integra en el propio runtime clientes nativos para Postgres, MySQL y SQLite, sin instalar nada. Analizamos qué ofrece Bun.sql frente a un ORM tradicional y en qué casos conviene quedarse solo con SQL.

📅 14 de mayo de 2026 ⏱️ 8 min de lectura ✍️ Equipo ProgramacionWebs

Durante años, hablar con una base de datos SQL desde Node.js significaba elegir entre dos caminos: instalar un driver de bajo nivel (pg, mysql2) y escribir consultas a mano, o instalar un ORM que te diera modelos, migraciones y tipado a cambio de una capa de abstracción adicional. Bun ha decidido que ese primer paso —el driver— no debería depender de ningún paquete de npm. Desde la versión 1.3, Bun.sql es un cliente nativo para PostgreSQL, MySQL y SQLite integrado directamente en el runtime, sin instalar nada y sin dependencias en el node_modules. No sustituye a un ORM, pero cambia la pregunta de partida: si el driver ya viene incluido y es rápido, ¿para qué proyectos sigue mereciendo la pena añadir una capa más encima?

Qué es exactamente Bun.sql

Bun.sql (accesible también como import { sql } from "bun") es un cliente SQL con API de plantillas etiquetadas (tagged templates), en la línea de lo que ya popularizó postgres.js en el ecosistema Node:

import { sql } from "bun";

const activeUsers = await sql`
  SELECT id, email, created_at
  FROM users
  WHERE active = ${true}
  ORDER BY created_at DESC
  LIMIT ${20}
`;

Los valores interpolados en la plantilla no se concatenan como texto: Bun los envía como parámetros vinculados al motor de base de datos, exactamente igual que haría un prepared statement clásico. Esto es lo que hace que esta forma de escribir SQL sea segura por defecto frente a inyección, siempre que no rompas el patrón concatenando strings manualmente antes de pasarlos a la plantilla.

Lo que soporta hoy, de forma nativa y sin paquetes adicionales:

  • PostgreSQL: autenticación SCRAM-SHA-256, LISTEN/NOTIFY, pool de conexiones configurable, conexiones reservadas con sql.reserve(), transacciones con savepoints y soporte para transacciones distribuidas (2PC).
  • MySQL (5.7+ y 8.0+): incorporado como driver nativo en Bun 1.3, con múltiples result sets, caché de prepared statements y negociación de plugins de autenticación.
  • SQLite: ejecución síncrona, soporte de PRAGMA y un sistema de tipos flexible, pensado para desarrollo local o aplicaciones embebidas.

Por qué esto es distinto de “otro driver más”

La diferencia no es solo técnica, es de distribución. pg o mysql2 son paquetes de npm que instalas, versionas y actualizas como cualquier otra dependencia; Bun.sql viene compilado dentro del binario del propio runtime, con las partes críticas de parseo de protocolo escritas en Zig y C++ en lugar de JavaScript. Esto se traduce en dos ventajas prácticas: cero instalación (nada que auditar en node_modules para hablar con la base de datos) y un rendimiento de bajo nivel más cercano al de un driver nativo compilado que al de una implementación en JavaScript puro sobre el runtime de V8.

La contrapartida es el acoplamiento: el código que usa Bun.sql directamente solo corre sobre Bun. Si tu aplicación necesita desplegarse también en Node.js, en un entorno serverless que no soporte Bun, o simplemente quieres mantener la opción abierta de cambiar de runtime en el futuro, esa portabilidad tiene un coste que hay que sopesar contra la ganancia de rendimiento.

Bun.sql frente a un ORM: qué capa resuelve cada cosa

Aquí es donde conviene ser preciso con el vocabulario, porque “ORM” y “driver” no compiten en la misma capa. Un ORM como Prisma o un query builder tipado como Drizzle se apoyan, por debajo, en un driver que habla el protocolo de red de la base de datos: ese driver puede ser pg, postgres.js… o, desde hace poco, el propio Bun.sql. De hecho, Drizzle ya soporta Bun.sql como uno de sus drivers de conexión, lo que significa que no es una elección binaria entre “Bun.sql” o “Drizzle”: puedes usar ambos juntos, con Drizzle aportando el esquema tipado y las migraciones, y Bun.sql como motor de conexión por debajo.

Dicho esto, la pregunta real que se plantea la mayoría de equipos es otra: ¿necesito la capa de abstracción de un ORM, o me basta con escribir SQL directamente contra Bun.sql? Ahí sí hay un trade-off real:

Solo Bun.sqlDrizzlePrisma
FilosofíaSQL directo, sin abstracciónQuery builder tipado, cercano al SQLEsquema declarativo, motor propio
MigracionesManuales (tus propios scripts SQL)drizzle-kit, genera SQL a partir del esquema TSMotor de migraciones propio, muy maduro
Tipado de resultadosManual (tú defines los tipos de retorno)Inferido automáticamente del esquemaGenerado a partir del esquema Prisma
Tamaño en el bundleNulo (viene en el runtime)Muy ligero (~7 KB con cero dependencias)Mayor, aunque Prisma 7 lo redujo bastante con su nuevo compilador TypeScript/WASM
Curva de aprendizajeNinguna si ya sabes SQLBaja si vienes de SQLMedia, hay que aprender su DSL y su cliente generado
Portabilidad de runtimeSolo BunNode, Bun, Deno, edgeNode, Bun (soporte edge más limitado)

Prisma 7 (finales de 2025) sustituyó su motor de consultas basado en Rust por un compilador en TypeScript/WASM, con mejoras de hasta 3,4 veces en velocidad de consulta y una reducción de tamaño de paquete cercana al 90% respecto a versiones anteriores. Sigue siendo, aun así, una capa más pesada que Drizzle o que usar Bun.sql desnudo, precisamente porque resuelve más cosas por ti: generación de cliente, migraciones declarativas, un motor de validación de esquema propio.

Cuándo tiene sentido prescindir del ORM

Ir sin ORM (o con un query builder mínimo por encima de Bun.sql) es una decisión razonable cuando se cumplen varias de estas condiciones a la vez, no solo una:

  • El equipo ya domina SQL y prefiere controlar exactamente qué consulta se ejecuta, sin depender de que el generador de consultas de un ORM produzca el plan óptimo (los JOIN generados automáticamente y el problema de N+1 queries son la fuente de dolor más habitual con ORMs mal usados).
  • El número de tablas y relaciones es manejable a mano. Un servicio pequeño con diez tablas no necesita un motor de migraciones declarativo; un monolito con doscientas sí se beneficia de tener el esquema como código versionado y generado.
  • El rendimiento y el arranque en frío importan de verdad: funciones serverless o edge donde cada milisegundo de cold start cuenta se benefician de no cargar un cliente generado ni un motor de consultas adicional.
  • Ya usas Bun como runtime de producción, no solo en local, y no hay planes de portar ese servicio a otro entorno a corto plazo.

Cuándo el ORM sigue ganando

Prescindir del ORM dejar de tener sentido, y conviene ser honesto al respecto, en estos escenarios:

  • Equipos grandes con muchos desarrolladores tocando el mismo esquema. Las migraciones declarativas y el tipado generado automáticamente evitan errores de sincronización entre el código y el estado real de la base de datos que, a mano, dependen de la disciplina de cada persona.
  • Aplicaciones con un dominio de datos complejo (relaciones profundas, herencia de tablas, validaciones de negocio ligadas al esquema) donde escribir y mantener SQL a mano para cada caso se vuelve más costoso que aprender la capa de abstracción.
  • Necesitas portabilidad de runtime real. Si el mismo código de acceso a datos debe correr en Node.js, en Bun y potencialmente en un entorno edge distinto, atarte a Bun.sql directamente introduce una dependencia de runtime que un ORM con múltiples drivers (o incluso Drizzle usando otro driver como postgres.js) evita.
  • El equipo es junior en SQL o rota con frecuencia. Un ORM con buen tipado actúa como red de seguridad: es más difícil escribir una consulta que compile pero sea semánticamente incorrecta cuando el compilador conoce el esquema completo.

Migraciones y esquema: la pieza que casi nunca se automatiza sola

Si decides prescindir de un ORM completo, el punto que hay que resolver explícitamente son las migraciones. Bun.sql no incluye ningún sistema de migraciones: es un cliente de conexión y ejecución, no un gestor de esquema. Las alternativas habituales son mantener una carpeta de archivos .sql numerados y aplicarlos en orden con un script propio, o usar una herramienta de migraciones independiente del ORM (como node-pg-migrate para Postgres) que no impone ningún query builder por encima. Lo que no es sostenible a medio plazo es no tener ningún proceso de migración versionado y aplicar cambios de esquema manualmente en producción: eso es exactamente el tipo de problema que un ORM resuelve de fábrica y que, si prescindes de él, tienes que resolver tú con la misma disciplina.

Para quien ya trabaja con PostgreSQL como base de datos por defecto —sigue siendo la opción más razonable para la mayoría de proyectos nuevos en 2026, como se explica en PostgreSQL en 2026: por qué sigue siendo la base de datos por defecto—, Bun.sql es una forma legítima de reducir una capa de dependencias sin perder seguridad frente a inyección ni rendimiento. La recomendación práctica: si tu proyecto ya vive en Bun y el esquema es manejable, prueba primero con Bun.sql puro o con Drizzle usándolo como driver; añade Prisma cuando el coste real de mantener el esquema a mano supere el beneficio de no tener una capa de abstracción encima.

Compartir