Drizzle ORM
Configuración de Drizzle en apps/api, los comandos db:* (generate, migrate, push, studio, seed) y el detalle de que db/index.ts importa cada schema explícitamente.
ixiclinic usa Drizzle ORM para el esquema y las consultas, y Drizzle Kit para las
migraciones. Toda la configuración vive en apps/api.
Configuración
El archivo apps/api/drizzle.config.ts define cómo Drizzle Kit encuentra el esquema y dónde
escribe las migraciones:
import { defineConfig } from 'drizzle-kit';
import { config } from 'dotenv';
config({ path: '.env.local' });
export default defineConfig({
schema: './src/db/schema/*',
out: './src/db/migrations',
dialect: 'postgresql',
dbCredentials: {
url: process.env.DATABASE_URL!,
},
});schema— apunta a./src/db/schema/*, es decir, todos los archivos de esquema por dominio.out— las migraciones generadas se escriben en./src/db/migrations.dialect—postgresql.dbCredentials.url— se lee deDATABASE_URL, cargada desde.env.local.
Comandos db:*
Definidos en apps/api/package.json. Ejecútalos desde apps/api:
| Comando | Qué hace |
|---|---|
pnpm db:generate | Genera un archivo de migración SQL a partir de los cambios en el esquema (drizzle-kit generate). |
pnpm db:migrate | Aplica las migraciones pendientes a la base apuntada por DATABASE_URL (drizzle-kit migrate). |
pnpm db:push | Empuja el esquema directamente a la base, sin generar migración. Solo desarrollo. |
pnpm db:studio | Abre Drizzle Studio, un explorador visual de la base. |
pnpm db:seed | Carga datos de ejemplo (tsx src/db/seed.ts). |
Existe además pnpm db:migrate:prod (node dist/migrate.js), que es el que ejecuta el
contenedor en producción; ver Migraciones.
Drizzle Studio
pnpm db:studio levanta un explorador web de la base de datos: permite inspeccionar tablas,
ver y editar filas y probar relaciones sin escribir SQL. Útil tanto contra la base de
desarrollo (Neon) como —con cuidado— contra cualquier base apuntada por DATABASE_URL.
La instancia db
La conexión y la instancia tipada de Drizzle se exportan desde apps/api/src/db/index.ts:
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';
import { env } from '../config/env.js';
import * as tenantSchema from './schema/tenants.js';
// ...un import por cada archivo de esquema...
const client = postgres(env.DATABASE_URL, {
ssl: env.DATABASE_URL.includes('sslmode=require') ? 'require' : undefined,
});
export const db = drizzle(client, {
schema: { ...tenantSchema, ...branchSchema, /* ...el resto... */ },
});
export type Database = typeof db;El cliente activa SSL automáticamente cuando la URL contiene sslmode=require (caso de Neon).
Gotcha: el glob no basta para db
Aunque drizzle.config.ts usa el glob ./src/db/schema/* para generar migraciones, la
instancia db en db/index.ts importa cada esquema explícitamente y los expande dentro
del objeto schema (...tenantSchema, ...branchSchema, etc.).
Esto significa que agregar un archivo nuevo a src/db/schema/ no lo hace visible para la
API de consultas relacionales de db automáticamente: hay que añadir su import * as ... y
su spread en db/index.ts. Si te olvidas, las migraciones se generan igual (el glob las ve),
pero db.query.<tabla> no conocerá esas tablas ni sus relaciones.
Nota: revisa que cada archivo de
src/db/schema/tenga su import y su spread endb/index.ts. Es un paso fácil de olvidar al introducir un dominio nuevo.
Para el flujo completo de migraciones ver Migraciones.
Base de datos
Visión general de la capa de datos de ixiclinic — Drizzle ORM sobre PostgreSQL, los dos entornos (desarrollo y producción) y el mapa de subpáginas.
Migraciones
Flujo generate → migrate de Drizzle, la migración automática en el arranque de producción, la función NCF de numeración fiscal, el riesgo de drift y la regla de aplicar todo cambio a ambas bases.