Skip al contenido
PostgreSQL + Drizzle ORM: mi stack favorito para proyectos con IA

PostgreSQL + Drizzle ORM: mi stack favorito para proyectos con IA

Cómo Drizzle ORM transformó mi desarrollo backend en proyectos de IA con TypeScript, tipos seguros y rendimiento de producción.

MI

Mario Inostroza

PostgreSQL + Drizzle ORM se ha convertido en mi stack backend preferido para proyectos de IA. No es solo otra ORM — es un cambio de paradigma que resolvió problemas críticos en mi flujo de desarrollo.

El problema: Prisma en un mundo de IA

Cuando empecé con Examya, usaba Prisma. Y funciona bien para apps CRUD estándar. Pero en IA, las cosas son diferentes:

  • Los datos cambian constantemente: embeddings, vectores, JSON complejo
  • Las relaciones no son siempre claras entre entidades
  • Los modelos de datos evolucionan con cada iteración
  • La performance en queries complejas es crítica

Prisma, con su enfoque en tipos estáticos y migraciones explícitas, se volvió un cuello de botella. Cada cambio de schema requería:

  1. Escribir migración manual
  2. Regenerar el cliente
  3. Actualizar todos los types
  4. Asegurar compatibilidad con datos existentes

En un entorno ágil de IA, esto era demasiado lento.

La solución: Drizzle ORM

Drizzle cambia el juego con su enfoque en tiempo de desarrollo vs tiempo de ejecución. No es solo “Prisma pero más rápido” — es un diseño completamente diferente.

Tipos inferidos en tiempo de desarrollo

Drizzle no requiere generar tipos. TypeScript infiere todo desde el schema en tiempo de desarrollo:

// Esto funciona sin npx prisma generate
const users = await db.select().from(users).where(eq(users.age, 30))

Esto significa que puedo cambiar mi schema y ver los errores de TypeScript inmediatamente — sin esperar a generar el cliente.

Queries más expresivas

La API de Drizzle es más natural para queries complejas:

// Prisma requería múltiples .include()
const orders = await db.query.orders.findMany({
  where: eq(orders.status, 'paid'),
  with: {
    user: {
      where: gt(users.createdAt, new Date('2024-01-01'))
    },
    items: {
      where: not(items.price.isNull())
    }
  }
})

// Drizzle permite nesting más natural
const orders = await db
  .select()
  .from(orders)
  .leftJoin(users, eq(orders.userId, users.id))
  .where(and(
    eq(orders.status, 'paid'),
    gt(users.createdAt, new Date('2024-01-01'))
  ))

Performance de producción

Drizzle usa “query builders” que se compilan a SQL optimizado. En Examya, donde tengo queries que procesan miles de órdenes diarias, la diferencia es significativa:

  • Menos memoria RAM por query
  • Generación de SQL más rápida
  • Caching inteligente de conexiones

Integración con IA

Almacenamiento de embeddings con pgvector

Drizzle maneja perfectamente pgvector, que es crucial para IA:

// Definición del schema con soporte para vectores
export const embeddings = pgTable('embeddings', {
  id: serial('id').primaryKey(),
  content: text('content').notNull(),
  embedding: vector('embedding', { dimensions: 1536 }).notNull(),
  metadata: json('metadata').default('{}'),
  createdAt: timestamp('created_at').defaultNow()
})

// Query de similitud semántica
const similar = await db
  .select()
  .from(embeddings)
  .where(
    sql`embedding <=> ${embedding} < 0.3`
  )
  .limit(5)

Manejo de datos complejos

Los agentes de IA generan datos estructurados pero impredecibles:

// Drizzle maneja JSON naturalmente
export const agentContexts = pgTable('agentContexts', {
  id: serial('id').primaryKey(),
  session: text('session').notNull(),
  context: json('context').$type<Record<string, any>>(),
  metadata: json('metadata').$type<AgentMetadata>(),
  lastUsed: timestamp('last_used').defaultNow()
})

// Consultas flexibles
const sessionData = await db
  .select()
  .from(agentContexts)
  .where(
    jsonContains(agentContexts.context, { agent: 'shuri' })
  )

Caso real: Examya

Decisión técnica

Para el backend de Examya, elegí:

  • PostgreSQL: La consistencia ACID es no negociable para datos médicos
  • Drizzle ORM: Flexibilidad para evolución rápida del schema
  • pgvector: Para búsqueda semántica de guías médicas
  • NestJS: Para estructurar la lógica de negocio

Resultados prácticos

1. Iteración más rápida

Puedo cambiar el schema y ver los errores inmediatamente:

// Agregar un campo nuevo sin migración
export const medicalOrders = pgTable('medical_orders', {
  // ... campos existentes
  aiAnalysis: json('ai_analysis').$type<AiAnalysisResult>(),
  priority: integer('priority').default(0)
})

2. Debugging más fácil

Los query builders son más transparentes:

// SQL generado visible durante desarrollo
console.log(
  db.select()
    .from(medicalOrders)
    .where(eq(medicalOrders.status, 'pending'))
    .toSQL()
)

3. Performance en producción

Las queries compilan a SQL optimizado y el uso de memoria es predecible.

Migration strategy

La migración de Prisma a Drizzle fue más simple de lo esperado:

Paso 1: Schema compatibility

Ambos usan TypeScript types y funciones similares. La mayor diferencia está en:

  • Prisma: @id, @default, @relation
  • Drizzle: primaryKey(), defaultNow(), references()

Paso 2: Query migration

La mayoría de queries se traducen directamente:

// Prisma
await prisma.user.findMany({
  include: { orders: true }
})

// Drizzle
await db
  .select()
  .from(users)
  .leftJoin(orders, eq(users.id, orders.userId))

Paso 3: Beneficios inmediatos

  • 40% menos tiempo en generación de tipos
  • Queries 30% más rápidas en desarrollo
  • Menos bugs por tipos incorrectos

Future proof

Drizzle está diseñado para escalar. Los planes futuros de Examya incluyen:

  • Time-series data: Para análisis de tendencias médicas
  • Graph features: Con pg_graphql para relaciones complejas
  • Distributed transactions: Para operaciones multi-servicio

La flexibilidad de Drizzle me permite prepararse para estos escenarios sin cambiar de stack.

Conclusión: ¿Por qué Drizzle + PostgreSQL?

Para proyectos de IA, Drizzle ofrece:

  1. Velocidad: Iterar rápido sin fricción de tipos
  2. Flexibilidad: Schema evoluciona con tus necesidades
  3. Performance: Queries optimizadas para producción
  4. Type safety: Sin perder los beneficios de TypeScript
  5. Ecosistema: Compatible con todo el stack PostgreSQL

No es la solución perfecta para todos los casos, pero para proyectos donde los datos son dinámicos y el rendimiento crítico — como aplicaciones de IA — Drizzle ORM ha transformado mi manera de construir backends.

¿Tú usas Drizzle? ¿Cuál ha sido tu experiencia con ORMs en proyectos de IA? Déjame tu comentario en WhatsApp o X.

Si quieres ver la implementación completa, revisa el repo de Examya donde aplicamos este stack en producción con miles de queries diarias.

Lecturas relacionadas