20 KiB
Evaluación de alternativas a Sequelize en Metis Desk
Fecha: 10 de octubre de 2026. Estado: estudio técnico; no se ha cambiado el ORM, instalado ninguna alternativa ni modificado la base de datos. Las conclusiones de encaje y esfuerzo son una valoración del código actual, no resultados de una migración o benchmark.
1. Recomendación
No recomiendo una sustitución completa inmediata. Recomiendo una prueba comparativa acotada de TypeORM y MikroORM, manteniendo MariaDB, las tablas, el dominio y los contratos HTTP. Si la prioridad es controlar SQL y reforzar su tipado, incluir Kysely en la prueba, reconociendo que es un constructor de consultas y no un ORM completo.
- TypeORM: camino más próximo al funcionamiento actual, con dialecto MariaDB explícito.
- MikroORM: candidato interesante para persistencia de relaciones y seguimiento de cambios; su beneficio debe compensar el contexto por petición y los modelos separados.
- Kysely: alternativa muy alineada con los repositorios que ya utilizan SQL explícito.
- Prisma 7: buen candidato para ergonomía de CRUD, condicionado por la transición de versiones y el uso intensivo de SQL/bloqueos del proyecto. Prisma 8 no entra en la prueba con MariaDB mientras su documentación indique ausencia de MySQL.
- Drizzle: atractivo para TypeScript y esquema relacional, pero no lo elegiría aquí sin validar primero compatibilidad MariaDB en consultas y migraciones.
- Sequelize 6: mantenerlo y mejorar aspectos concretos sigue siendo una opción válida.
La decisión debe salir de medir menos código de persistencia, mejores tipos y mantenimiento, sin perder garantías de concurrencia; no de elegir el ORM con ejemplos de CRUD más breves.
2. Situación real del proyecto
La inspección del repositorio muestra:
| Aspecto | Estado observado | Consecuencia |
|---|---|---|
| ORM y motor | Sequelize 6.37.8; driver mariadb 3.5.4; contenedor MariaDB 11.8 | Comparar contra esta combinación, no contra PostgreSQL ni un ejemplo SQLite. |
| Acoplamiento | 90 ficheros de servidor importan o mencionan Sequelize; 24 implementaciones de repositorio tienen nombre sequelize-*.repository.ts |
El cambio afecta a bastantes piezas aunque la frontera arquitectónica esté bien definida. Los números son de código fuente, no de tablas. |
| Capas | Puertos en Application; modelos ORM y mappers en Infrastructure; dominio DDD propio | La mayoría de entidades, Value Objects y casos de uso deberían conservarse. |
| Persistencia | Combinación de Model, consultas SQL parametrizadas, helpers relacionales y transacciones | Una sustitución no consiste solo en regenerar entidades. |
| Concurrencia | FOR UPDATE, bloqueos del catálogo y orden fijo de adquisición |
Deben reproducirse dentro de la misma transacción/conexión. |
| Históricos | Revisiones de activos y asignaciones, entre otros | Deben mantenerse identidad, orden e inmutabilidad del histórico. |
| Sesiones | connect-session-sequelize 8.0.6 sobre http_sessions |
Eliminar Sequelize completamente requiere sustituir o adaptar el store de Express. |
| Normalización | La persistencia de negocio utiliza columnas y tablas relacionadas | La elección de ORM debe conservar el diseño relacional y sus restricciones. |
Fuentes locales principales: apps/server/src/infrastructure/http/identity-runtime.ts,
modules/assets/src/api/infrastructure/persistence/sequelize-asset.repository.ts,
sequelize-brand.repository.ts, asset-inventory-relational.ts,
modules/companies/src/api/infrastructure/persistence/sequelize-dashboard.repository.ts,
modules/resources/src/api/infrastructure/persistence/resource-catalog.model.ts y
docs/arquitectura/capas-del-servidor.md.
El dominio sigue utilizando UniqueID, Result, Maybe y mappers. Ningún ORM debería
sustituir esos contratos ni generar nuevos UUID con otra estrategia por defecto.
3. Comparación resumida
Las valoraciones de esfuerzo son relativas a Metis Desk y abarcan reescritura y validación, no solo conexión inicial. No son métricas objetivas de calidad universal.
| Alternativa | MariaDB | Ventaja principal aquí | Coste de adaptación | Valoración |
|---|---|---|---|---|
| Sequelize 6 | Dialecto actual ya operativo | Continuidad y menor riesgo | Bajo si se mantiene | Referencia contra la que medir el beneficio. |
| TypeORM | Soporte explícito | Modelo/repository/query builder reconocibles | Medio | Primera prueba si se busca migrar con menor distancia conceptual. |
| MikroORM | Driver explícito | Unit of Work, relaciones y seguimiento de cambios | Medio-alto | Primera prueba si se busca mejorar mantenibilidad de persistencia compleja. |
| Prisma 7 | Conector MySQL admite MariaDB | Cliente generado y CRUD tipado | Medio-alto | Condicionado por versiones y consultas específicas. |
| Prisma 8 | Documentación consultada: sin MySQL | No aplicable al motor actual | No evaluable aquí | Excluido de la propuesta actual. |
| Drizzle | Integración documentada MySQL/mysql2; soporte específico MariaDB pendiente de verificar | Esquemas TypeScript y consultas próximas a SQL | Medio; riesgo adicional de dialecto | No primera elección con MariaDB. |
| Kysely | Dialecto MySQL/mysql2; comprobar diferencias MariaDB | Consultas SQL compuestas y tipadas | Medio | Buena alternativa cuando importa más SQL que gestión automática de objetos. |
4. Sequelize: mantener o actualizar
Ventajas: funciona con el motor y las sesiones actuales; los errores y transacciones ya están integrados; dispone de inferencia de atributos TypeScript, que el proyecto utiliza. Su documentación reconoce que determinadas declaraciones de modelo siguen requiriendo trabajo manual. TypeScript en Sequelize 6.
Inconvenientes en este proyecto: se repiten definiciones entre modelos y tipos;
database.query<T> declara un tipo de resultado, pero no demuestra que el SQL devuelva
esas columnas; las migraciones y helpers necesitan disciplina propia.
Mejoras sin migración: separar el ejecutor de SQL de consultas concretas, reutilizar mappers reales y revisar transacciones/lecturas excesivas. No crear un repositorio genérico que oculte reglas de negocio o bloqueos. No atribuir a Sequelize costes de consultas que cargan todo un contexto de inventario: cambiar el ORM no evita esa decisión de diseño.
Actualización a v7: es un camino distinto de cambiar de ORM. La documentación consultada sigue etiquetándola como alpha; no la tomaría como actualización automática del proyecto. Estado de Sequelize 7.
5. TypeORM
Capacidades verificadas
Tiene soporte explícito MySQL/MariaDB, configuración type: "mariadb" y driver mysql2.
Permite definir entidades mediante EntitySchema, sin imponer decoradores. Incluye
migraciones, query builder y transacciones; las operaciones transaccionales deben usar el
manager proporcionado por la transacción.
MariaDB,
EntitySchema,
transacciones,
migraciones.
Ventajas para Metis Desk
- Sustitución relativamente directa de modelos y repositorios de infraestructura.
- Permite conservar SQL particular donde aporte claridad.
- Es posible mantener entidades de persistencia separadas del dominio DDD.
- Su dialecto MariaDB reduce incertidumbre respecto a una integración solo MySQL.
Inconvenientes y adaptación
Seguirán existiendo modelos de persistencia y mappers; no desaparece toda la duplicación. Los resultados de consultas SQL crudas tampoco quedan automáticamente validados. Las cascadas, relaciones y métodos de guardado deben configurarse expresamente para no modificar históricos o borrar registros relacionados por accidente.
Reescribiríamos modelos, repositorios, composición de módulos, conexión y migraciones;
revisaríamos traducción de errores de FK/unique y semántica de upsert. Evitaríamos Active
Record dentro del dominio y synchronize como sustituto de migraciones. La documentación
actual anuncia TypeORM 1.0: fijaríamos una versión concreta y sus instrucciones, sin mezclar
ejemplos antiguos de 0.2/0.3 con la API elegida.
Valoración: el reemplazo convencional más cercano al código actual. La ganancia principal sería ergonomía y consistencia, no una transformación radical de la arquitectura.
6. MikroORM
Capacidades verificadas
Dispone de driver MariaDB, Unit of Work e Identity Map. Puede calcular los cambios de
entidades gestionadas al hacer flush; ofrece migraciones y generación de entidades desde
el esquema. La definición defineEntity permite inferir tipos sin decoradores.
Arquitectura y drivers,
Unit of Work,
defineEntity,
generador,
migraciones.
Ventajas para Metis Desk
- Interesante para persistir conjuntos relacionados sin repetir tantas operaciones de guardado.
- El seguimiento de cambios puede ayudar a actualizar únicamente entidades modificadas.
- Herramientas para definir, generar y evolucionar el esquema.
- Buen candidato para relaciones complejas si se mantiene clara la separación entre dominio y representación persistida.
Inconvenientes y adaptación
Requiere comprender el ciclo de vida de las entidades gestionadas y sus colecciones. La Identity Map debe aislarse por petición, mediante fork/contexto; un EntityManager global compartido sin aislamiento no es aceptable. Contexto por petición.
Las entidades DDD actuales no se convertirían directamente en entidades gestionadas: se mantendrían mappers. Si un mapper crea una representación persistida completamente nueva en cada guardado, parte de las ventajas del seguimiento de cambios se reduce. La prueba debe resolver este punto, no suponer que Unit of Work elimina todos los mappers.
Reescribiríamos modelos/repositorios y añadiríamos contexto por petición, respetando límites transaccionales. Las revisiones continuarían como registros explícitos; una cascada de borrado no sustituye las reglas del histórico. Los bloqueos existentes seguirían siendo necesarios.
Valoración: candidato con ventajas potenciales de persistencia más profundas, a cambio de mayor aprendizaje e integración que TypeORM. No introducir sus abstracciones en Domain.
7. Prisma: distinguir versiones
Capacidades y situación verificadas
Prisma 7 documenta MariaDB mediante el conector MySQL y el adaptador mariadb. Ofrece introspección, cliente generado, transacciones interactivas y baseline para adoptar una BD existente sin recrearla. Conector v7, transacciones v7, baseline v7.
La documentación principal ya presenta Prisma 8 y el repositorio publica versiones RC.
La página actual de transacciones indica que Prisma 8 no tiene soporte MySQL. No se debe
suponer que instalar latest conserva compatibilidad MariaDB ni trasladar ejemplos v7 a v8.
Releases,
documentación actual de transacciones.
Ventajas de evaluar v7
- Buen autocompletado y selección tipada de campos en el cliente generado.
- CRUD y relaciones sencillas pueden expresarse de forma compacta.
- Introspección útil para comenzar a partir de nuestras tablas.
- Esquema declarativo e historial de migraciones formalizado.
Inconvenientes y adaptación
Añade un esquema propio y un paso de generación al monorepo. Los modelos generados no reemplazan entidades DDD ni DTOs Zod. Las consultas particulares del dashboard y el orden de bloqueos del inventario requerirían revisión y, donde proceda, SQL parametrizado dentro de la misma transacción; no basta con sustituirlas por escrituras anidadas de CRUD.
La introspección no genera reglas de negocio ni reconstruye las migraciones históricas de Sequelize. Hay que revisar tipos físicos, restricciones e índices y preservar aquellos elementos no representados por el esquema. Existe además incertidumbre de evolución de versiones que debe resolverse antes de elegirlo para un motor MariaDB a largo plazo.
Valoración: atractivo para aplicaciones CRUD, pero no el candidato principal ahora. Prisma 7 podría evaluarse fijando versión; Prisma 8 queda fuera por el motor actual.
8. Drizzle
Capacidades verificadas
Declara el esquema en TypeScript y ofrece consultas cercanas a SQL. La integración oficial consultada es MySQL con mysql2; Drizzle Kit puede introspectar una base existente. MySQL, introspección.
Hay una petición abierta para comportamiento específico MariaDB y reportes de incompatibilidad con consultas relacionales basadas en LATERAL. Es evidencia de un área que requiere validación, no una prueba de que cualquier consulta Drizzle falle en MariaDB ni de que el problema afecte a todas las versiones/APIs. Issue del proyecto.
Ventajas e inconvenientes para Metis Desk
Su enfoque resulta afín a una BD normalizada y a infraestructura que ya usa SQL. Evita imponer entidades gestionadas y decoradores. No elimina mappers ni reglas de guardado de agregados y no aporta Unit of Work al estilo MikroORM.
La dificultad extra aquí es verificar diferencias MariaDB/MySQL en generación de SQL, introspección, tipos y migraciones. Conservaría SQL explícito donde fuese necesario y no usaría una API relacional sin comprobar su SQL en MariaDB 11.8. La documentación consultada contiene ejemplos con paquetes RC: fijaríamos una versión y separaríamos APIs estables y RC.
Valoración: buena propuesta técnica si la prueba de compatibilidad es satisfactoria; menor prioridad que los candidatos con soporte MariaDB explícito.
9. Kysely, Knex y Objection.js
Kysely no es un ORM de entidades. Es un constructor SQL tipado; su dialecto MySQL usa mysql2. Sus tipos actúan en compilación y el driver determina los valores reales devueltos. Introducción, drivers y tipos.
Para Metis Desk, permite mantener el control sobre joins, proyecciones y escrituras de históricos, mejorando el tipado frente a SQL en strings. Su coste es seguir implementando mapeo, persistencia de relaciones y cambios de esquema; los tipos de tabla deben mantenerse alineados con la BD. Al emplear el dialecto MySQL, también hay que probar funciones y SQL específico de MariaDB. El problema de consultas relacionales automáticas de Drizzle no se traslada por sí solo a Kysely: son implementaciones distintas.
Valoración: potencialmente la opción más sencilla si lo que queremos sustituir es el uso de Sequelize como ejecutor SQL. Menos apropiada si buscamos guardado automático de objetos relacionados.
Knex cubre consultas/migraciones; Objection.js añade un ORM sobre Knex y deja las migraciones del esquema a esa capa. Podrían sustituir partes del proyecto, pero no los priorizaría sin una necesidad concreta frente a la prueba de Kysely/TypeORM/MikroORM. Diseño de Objection.js y migraciones. Esta es una priorización por encaje, no una afirmación de falta de mantenimiento.
10. Riesgos comunes de la migración
- Transacciones: no mezclar operaciones Sequelize y el nuevo cliente dentro de una operación que necesita atomicidad. Dos pools no comparten automáticamente una transacción.
- Bloqueos: preservar el orden catálogo → compañía → registros y comprobar la semántica
de
FOR UPDATE, especialmente al eliminar marcas mientras se crean activos. - Migrations: durante coexistencia, mantener una única autoridad para cada tabla. No ejecutar dos generadores sobre las mismas tablas ni emplear sync/push para recrearlas.
- Tipos físicos: revisar UUID actuales, booleanos TINYINT, fechas sin hora, precisión de timestamps/decimales, nulabilidad y collation. No cambiar su representación por comodidad.
- Errores: conservar conflictos de unicidad/FK, códigos de aplicación y datos seguros.
- Históricos: preservar UUID, orden, fechas, usuario actor y referencias aunque un valor de catálogo se desactive.
- Sesiones: inicialmente puede seguir el store Sequelize. Para retirar la dependencia completamente habría que reemplazarlo preservando expiración, cookies y validación de sesiones, o asumir un cierre de sesiones controlado. No usar MemoryStore como reemplazo.
- Modelo relacional: preservar el diseño de columnas, tablas dependientes y restricciones. Ninguna herramienta garantiza una BD normalizada por usarla.
- Rendimiento: medir número de consultas, tiempo y filas leídas con datos equivalentes; no afirmar que un ORM es más rápido solo por su API.
11. Prueba propuesta antes de decidir
No ejecutada en este informe. Usaría una copia de prueba de la BD, sin tocar desarrollo.
Casos representativos
- Marcas: listar, crear, actualizar y rechazar borrado referenciado. Incluye bloqueos y restricciones, por lo que da más información que un CRUD de ejemplo.
- Un activo: características normalizadas, plantilla con campos opcionales e histórico.
- Lectura de dashboard: consultas con agregaciones y parámetros de compañía.
- Concurrencia: dos solicitudes sobre el mismo catálogo/activo y fallo a mitad del guardado.
Los candidatos implementarían los mismos puertos. Primero reutilizaríamos los tests de contrato, dominio e integración existentes; después añadiríamos casos de concurrencia que falten. No sustituir MariaDB por SQLite para concluir compatibilidad.
Criterios de aceptación
- Mismos datos, contratos HTTP, historial y reglas de borrado.
- Sin cambios accidentales en DDL al adoptar el ORM.
- Rollback completo y bloqueos equivalentes.
- Menos declaraciones duplicadas o guardados manuales en un caso real.
- Mejor detección de errores de columnas/resultados en TypeScript.
- Consultas y tiempos comparables bajo el mismo volumen.
- Inicialización, cierre de conexiones, migraciones y pruebas reproducibles con Node 24/PNPM.
Como estimación de planificación, dedicaría unas pocas jornadas a una prueba acotada y reservaría varias semanas para una migración completa y validación de los 24 repositorios nombrados y sus helpers. No es un presupuesto: el inventario detallado de tablas y el piloto son necesarios para convertirlo en una estimación fiable.
12. Ruta de adopción si la prueba resulta favorable
- Fijar candidato/versión y actualizar las decisiones de arquitectura que hoy prescriben Sequelize; no empezar mezclando estilos sin una decisión explícita.
- Inventariar esquema y migraciones; crear baseline verificado con DDL y datos de prueba.
- Migrar un módulo o un conjunto transaccional completo, manteniendo los puertos y mappers.
- Repetir integración sobre MariaDB y comparar concurrencia/consultas.
- Ampliar por módulos; conservar Sequelize temporalmente para partes no migradas.
- Sustituir el store de sesiones y retirar la conexión/dependencia cuando no queden usos.
- Retirar la antigua ejecución de migraciones sin perder su historial ni trazabilidad.
Conclusión: TypeORM ofrece el recorrido más cercano; MikroORM debe demostrar mayor ahorro en persistencia compleja; Kysely puede ser la elección más coherente si preferimos SQL explícito. Mantener Sequelize sigue siendo preferible a una migración que solo cambie la sintaxis y no reduzca la complejidad real.