From d1c4e3bc4d3a17530bc0ef619ae11555ed5db820 Mon Sep 17 00:00:00 2001 From: Tobias Jensen Date: Tue, 17 Feb 2026 19:28:36 +0100 Subject: [PATCH 1/3] feat(cli): add dialect option for db generate --- cli/commands/db/generate.mjs | 60 +++++++++++++++++++++++++++--------- src/db/setup.ts | 2 ++ 2 files changed, 47 insertions(+), 15 deletions(-) diff --git a/cli/commands/db/generate.mjs b/cli/commands/db/generate.mjs index e408f5fdf..cd0ffe8de 100644 --- a/cli/commands/db/generate.mjs +++ b/cli/commands/db/generate.mjs @@ -31,6 +31,11 @@ export default defineCommand({ type: 'boolean', description: 'Show verbose output.', required: false + }, + dialect: { + type: 'string', + description: 'Database dialect, one of postgresql mysql sqlite', + required: false } }, async run({ args }) { @@ -43,23 +48,48 @@ export default defineCommand({ stdout: 'pipe', stderr: 'pipe', preferLocal: true, - cwd + cwd, + env: { + ...process.env, + ...(args.dialect ? { NUXT_HUB_DB: args.dialect } : {}) + } + } + + async function GenerateMigration(dialect) { + consola.info(`Ensuring database schema is generated${dialect ? ' for ' + dialect : ''}...`) + await execa(options)`nuxt prepare` + const alias = await getTsconfigAliases(cwd) + await buildDatabaseSchema(join(options.cwd, '.nuxt'), { relativeDir: cwd, alias }) + consola.info(`Generating database migrations${dialect ? ' for ' + dialect : ''}...`) + const { stderr } = await execa({ + ...options, + stdin: 'inherit', + stdout: 'inherit' + })`drizzle-kit generate --config=./.nuxt/hub/db/drizzle.config.ts${args.custom ? ' --custom' : ''}${args.name ? ` --name=${args.name}` : ''}` + // Drizzle-kit does not exit with an error code when there is an error, so we need to check the stderr + if (stderr) { + consola.error(stderr) + process.exit(1) + } } - consola.info('Ensuring database schema is generated...') - await execa(options)`nuxt prepare` - const alias = await getTsconfigAliases(cwd) - await buildDatabaseSchema(join(options.cwd, '.nuxt'), { relativeDir: cwd, alias }) - consola.info('Generating database migrations...') - const { stderr } = await execa({ - ...options, - stdin: 'inherit', - stdout: 'inherit' - })`drizzle-kit generate --config=./.nuxt/hub/db/drizzle.config.ts${args.custom ? ' --custom' : ''}${args.name ? ` --name=${args.name}` : ''}` - // Drizzle-kit does not exit with an error code when there is an error, so we need to check the stderr - if (stderr) { - consola.error(stderr) - process.exit(1) + + if (args.dialect === "all") { + for (dialect in ["postgresql", "mysql", "sqlite"]) { + await GenerateMigration(dialect) + } + } else { + await GenerateMigration(args.dialect) } + + + if (args.dialect) { + consola.info('Resetting .nuxt with original db dialect') + await execa({ + ...options, + env: {} + })`nuxt prepare` + } + consola.success('Database migrations generated successfully.') consola.info('Run `npx nuxt dev` or run `npx nuxt db migrate` to apply the migrations.') } diff --git a/src/db/setup.ts b/src/db/setup.ts index 514910bb3..6ccfde97f 100644 --- a/src/db/setup.ts +++ b/src/db/setup.ts @@ -39,6 +39,8 @@ export { db, schema } * Resolve database configuration from string or object format */ export async function resolveDatabaseConfig(nuxt: Nuxt, hub: HubConfig): Promise { + // Env explicitly set db. Used by cli db generate command + if(process.env.NUXT_HUB_DB) hub.db = process.env.NUXT_HUB_DB if (!hub.db) return false let config = typeof hub.db === 'string' ? { dialect: hub.db } : hub.db From 47c5eb40ddb2f1319eaccb243ed05aabd59e2430 Mon Sep 17 00:00:00 2001 From: Tobias Jensen Date: Tue, 17 Feb 2026 19:56:45 +0100 Subject: [PATCH 2/3] feat(cli): cleanup generate dialect --- cli/commands/db/generate.mjs | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/cli/commands/db/generate.mjs b/cli/commands/db/generate.mjs index cd0ffe8de..1ad9c1651 100644 --- a/cli/commands/db/generate.mjs +++ b/cli/commands/db/generate.mjs @@ -33,10 +33,11 @@ export default defineCommand({ required: false }, dialect: { - type: 'string', + type: 'enum', + options: ["sqlite", "postgresql", "mysql", "all"], description: 'Database dialect, one of postgresql mysql sqlite', required: false - } + }, }, async run({ args }) { if (args.verbose) { @@ -44,18 +45,20 @@ export default defineCommand({ consola.level = 4 } const cwd = args.cwd ? resolve(process.cwd(), args.cwd) : process.cwd() - const options = { + let options = { stdout: 'pipe', stderr: 'pipe', preferLocal: true, cwd, - env: { - ...process.env, - ...(args.dialect ? { NUXT_HUB_DB: args.dialect } : {}) - } + env: {} } async function GenerateMigration(dialect) { + if (dialect) + options.env = { + ...process.env, + NUXT_HUB_DB: dialect + } consola.info(`Ensuring database schema is generated${dialect ? ' for ' + dialect : ''}...`) await execa(options)`nuxt prepare` const alias = await getTsconfigAliases(cwd) @@ -71,11 +74,12 @@ export default defineCommand({ consola.error(stderr) process.exit(1) } + delete options.env.NUXT_HUB_DB } if (args.dialect === "all") { - for (dialect in ["postgresql", "mysql", "sqlite"]) { - await GenerateMigration(dialect) + for (const _dialect of ["sqlite", "postgresql", "mysql"]) { + await GenerateMigration(_dialect) } } else { await GenerateMigration(args.dialect) @@ -84,10 +88,7 @@ export default defineCommand({ if (args.dialect) { consola.info('Resetting .nuxt with original db dialect') - await execa({ - ...options, - env: {} - })`nuxt prepare` + await execa(options)`nuxt prepare` } consola.success('Database migrations generated successfully.') From 6e9e2b0aee0a8a090242d6d0e5dfe5598555d556 Mon Sep 17 00:00:00 2001 From: Tobias Jensen Date: Tue, 17 Feb 2026 23:21:12 +0100 Subject: [PATCH 3/3] feat(db): support drizzle config properties passed to generated config --- src/db/setup.ts | 20 ++++++++++++++------ src/types/config.ts | 10 ++++++++++ 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/db/setup.ts b/src/db/setup.ts index 6ccfde97f..8dea4a36c 100644 --- a/src/db/setup.ts +++ b/src/db/setup.ts @@ -7,6 +7,7 @@ import { addServerImports, addTemplate, addServerPlugin, addTypeTemplate, getLay import { resolve, resolvePath, logWhenReady, addWranglerBinding } from '../utils' import { copyDatabaseMigrationsToHubDir, copyDatabaseQueriesToHubDir, copyDatabaseAssets, applyBuildTimeMigrations, getDatabaseSchemaPathMetadata, buildDatabaseSchema } from './lib' import { cloudflareHooks } from '../hosting/cloudflare' +import { stringifyJSON5 } from "confbox" import type { Nuxt } from '@nuxt/schema' import type { HubConfig, ResolvedHubConfig, ResolvedDatabaseConfig } from '@nuxthub/core' @@ -637,16 +638,23 @@ export const db: ReturnType> async function setupDatabaseConfig(nuxt: Nuxt, hub: ResolvedHubConfig) { // generate drizzle.config.ts in .nuxt/hub/db/drizzle.config.ts - const { dialect, casing } = hub.db as ResolvedDatabaseConfig - const casingConfig = casing ? `\n casing: '${casing}',` : '' + const { dialect, casing, drizzle } = hub.db as ResolvedDatabaseConfig + addTemplate({ filename: 'hub/db/drizzle.config.ts', write: true, getContents: () => `import { defineConfig } from 'drizzle-kit' -export default defineConfig({ - dialect: '${dialect}',${casingConfig} - schema: '${relative(nuxt.options.rootDir, resolve(nuxt.options.buildDir, 'hub/db/schema.mjs'))}', - out: '${relative(nuxt.options.rootDir, resolve(nuxt.options.rootDir, `server/db/migrations/${dialect}`))}' +export default defineConfig(${ + stringifyJSON5( + defu(drizzle, + casing && { casing }, + { + dialect, + schema: relative(nuxt.options.rootDir, resolve(nuxt.options.buildDir, 'hub/db/schema.mjs')), + out: relative(nuxt.options.rootDir, resolve(nuxt.options.rootDir, `server/db/migrations/${dialect}`)) + } + ) + ) });` }) } diff --git a/src/types/config.ts b/src/types/config.ts index c0edaa201..0dcd7df5b 100644 --- a/src/types/config.ts +++ b/src/types/config.ts @@ -3,6 +3,7 @@ import type { FSDriverOptions } from '@nuxthub/core/blob/drivers/fs' import type { S3DriverOptions } from '@nuxthub/core/blob/drivers/s3' import type { VercelDriverOptions } from '@nuxthub/core/blob/drivers/vercel-blob' import type { CloudflareDriverOptions } from '@nuxthub/core/blob/drivers/cloudflare-r2' +import type { Config as DrizzleConfig } from "drizzle-kit" export interface HubConfig { blob: boolean | BlobConfig @@ -224,6 +225,15 @@ export type DatabaseConfig = { * @see https://orm.drizzle.team/docs/read-replicas */ replicas?: string[] + /** + * Drizzle config that will be passed down to the generated drizzle.config.ts + * + * @see https://orm.drizzle.team/docs/drizzle-config-file + */ + drizzle?: Pick< + DrizzleConfig, + "entities" | "schemaFilter" | "tablesFilter" | "extensionsFilters" + >; } export type ResolvedDatabaseConfig = DatabaseConfig & {