ixiclinicDocs
DesarrolladoresBase de datos

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.
  • dialectpostgresql.
  • dbCredentials.url — se lee de DATABASE_URL, cargada desde .env.local.

Comandos db:*

Definidos en apps/api/package.json. Ejecútalos desde apps/api:

ComandoQué hace
pnpm db:generateGenera un archivo de migración SQL a partir de los cambios en el esquema (drizzle-kit generate).
pnpm db:migrateAplica las migraciones pendientes a la base apuntada por DATABASE_URL (drizzle-kit migrate).
pnpm db:pushEmpuja el esquema directamente a la base, sin generar migración. Solo desarrollo.
pnpm db:studioAbre Drizzle Studio, un explorador visual de la base.
pnpm db:seedCarga 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 en db/index.ts. Es un paso fácil de olvidar al introducir un dominio nuevo.

Para el flujo completo de migraciones ver Migraciones.

On this page