diff --git a/.changeset/skip-disabled-migration-tables.md b/.changeset/skip-disabled-migration-tables.md new file mode 100644 index 0000000000..7f9fcd517f --- /dev/null +++ b/.changeset/skip-disabled-migration-tables.md @@ -0,0 +1,7 @@ +--- +"better-auth": patch +"@better-auth/core": patch +"auth": patch +--- + +Honor `disableMigration` on plugin schema tables. Tables flagged with `disableMigration: true` are now skipped by `better-auth generate` (Drizzle and Prisma output) and by the runtime migrator, instead of being emitted and created anyway. The flag was previously dropped while assembling the table list, so it had no effect. diff --git a/packages/better-auth/src/db/get-migration.ts b/packages/better-auth/src/db/get-migration.ts index 15cdcaaada..e1a678f91f 100644 --- a/packages/better-auth/src/db/get-migration.ts +++ b/packages/better-auth/src/db/get-migration.ts @@ -224,6 +224,9 @@ export async function getMigrations(config: BetterAuthOptions) { }[] = []; for (const [key, value] of Object.entries(betterAuthSchema)) { + if (value.disableMigrations) { + continue; + } const table = tableMetadata.find((t) => t.name === key); if (!table) { const tIndex = toBeCreated.findIndex((t) => t.table === key); diff --git a/packages/better-auth/src/db/get-schema.ts b/packages/better-auth/src/db/get-schema.ts index 84a3270e68..8bfce24b1a 100644 --- a/packages/better-auth/src/db/get-schema.ts +++ b/packages/better-auth/src/db/get-schema.ts @@ -9,6 +9,7 @@ export function getSchema(config: BetterAuthOptions) { { fields: Record; order: number; + disableMigrations?: boolean | undefined; } > = {}; for (const key in tables) { @@ -33,11 +34,15 @@ export function getSchema(config: BetterAuthOptions) { ...schema[table.modelName]!.fields, ...actualFields, }; + if (table.disableMigrations) { + schema[table.modelName]!.disableMigrations = true; + } continue; } schema[table.modelName] = { fields: actualFields, order: table.order || Infinity, + disableMigrations: table.disableMigrations, }; } return schema; diff --git a/packages/cli/src/generators/drizzle.ts b/packages/cli/src/generators/drizzle.ts index 2ef387beb5..8020aa69fa 100644 --- a/packages/cli/src/generators/drizzle.ts +++ b/packages/cli/src/generators/drizzle.ts @@ -46,6 +46,9 @@ export const generateDrizzleSchema: SchemaGenerator = async ({ for (const tableKey in tables) { const table = tables[tableKey]!; + if (table.disableMigrations) { + continue; + } const modelName = getModelName(tableKey); const fields = table.fields; @@ -293,6 +296,9 @@ export const generateDrizzleSchema: SchemaGenerator = async ({ let relationsString: string = ""; for (const tableKey in tables) { const table = tables[tableKey]!; + if (table.disableMigrations) { + continue; + } const modelName = getModelName(tableKey); type Relation = { diff --git a/packages/cli/src/generators/prisma.ts b/packages/cli/src/generators/prisma.ts index 1981a64ccf..91dbf4c5a5 100644 --- a/packages/cli/src/generators/prisma.ts +++ b/packages/cli/src/generators/prisma.ts @@ -117,6 +117,9 @@ export const generatePrismaSchema: SchemaGenerator = async ({ const schema = produceSchema(schemaPrisma, (builder) => { for (const table in tables) { + if (tables[table]?.disableMigrations) { + continue; + } const originalTableName = table; const customModelName = tables[table]?.modelName || table; const modelName = capitalizeFirstLetter(getModelName(customModelName)); diff --git a/packages/cli/test/generate.test.ts b/packages/cli/test/generate.test.ts index c2ebd4eed8..66a409e341 100644 --- a/packages/cli/test/generate.test.ts +++ b/packages/cli/test/generate.test.ts @@ -1684,4 +1684,58 @@ describe("--dialect flag support", () => { expect(schema.code).toContain('provider = "mysql"'); expect(schema.fileName).toBe("test.prisma"); }); + + const pluginWithDisabledMigration = (): BetterAuthPlugin => ({ + id: "disabled-migration-test", + schema: { + emittedTable: { + fields: { + name: { type: "string", required: true }, + }, + }, + skippedTable: { + fields: { + name: { type: "string", required: true }, + }, + disableMigration: true, + }, + }, + }); + + it("should not emit drizzle tables with disableMigration", async () => { + const schema = await generateDrizzleSchema({ + file: "test.drizzle", + adapter: { + id: "drizzle", + options: { + provider: "pg", + schema: {}, + }, + } as any, + options: { + database: {} as any, + plugins: [pluginWithDisabledMigration()], + } as BetterAuthOptions, + }); + + expect(schema.code).toContain("emittedTable"); + expect(schema.code).not.toContain("skippedTable"); + }); + + it("should not emit prisma models with disableMigration", async () => { + const schema = await generatePrismaSchema({ + file: "test.prisma", + adapter: prismaAdapter( + {}, + { provider: "postgresql" }, + )({} as BetterAuthOptions), + options: { + database: prismaAdapter({}, { provider: "postgresql" }), + plugins: [pluginWithDisabledMigration()], + }, + }); + + expect(schema.code).toContain("EmittedTable"); + expect(schema.code).not.toContain("SkippedTable"); + }); }); diff --git a/packages/core/src/db/get-tables.ts b/packages/core/src/db/get-tables.ts index bdf39e3904..5573e00e95 100644 --- a/packages/core/src/db/get-tables.ts +++ b/packages/core/src/db/get-tables.ts @@ -15,13 +15,19 @@ export const getAuthTables = ( ...value.fields, }, modelName: value.modelName || key, + disableMigrations: + value.disableMigration ?? acc[key]?.disableMigrations, }; } return acc; }, {} as Record< string, - { fields: Record; modelName: string } + { + fields: Record; + modelName: string; + disableMigrations?: boolean | undefined; + } >, ); diff --git a/packages/core/src/db/test/get-tables.test.ts b/packages/core/src/db/test/get-tables.test.ts index 7762a89b24..4374f07060 100644 --- a/packages/core/src/db/test/get-tables.test.ts +++ b/packages/core/src/db/test/get-tables.test.ts @@ -113,4 +113,52 @@ describe("getAuthTables", () => { expect(tables.verification).toBeDefined(); }); + + it("should propagate disableMigration from a plugin schema onto the table", () => { + const tables = getAuthTables({ + plugins: [ + { + id: "test", + schema: { + skipped: { + fields: { name: { type: "string" } }, + disableMigration: true, + }, + kept: { + fields: { name: { type: "string" } }, + }, + }, + }, + ], + }); + + expect(tables.skipped!.disableMigrations).toBe(true); + expect(tables.kept!.disableMigrations).toBeUndefined(); + }); + + it("should keep disableMigration when plugins accumulate the same table key", () => { + const tables = getAuthTables({ + plugins: [ + { + id: "a", + schema: { + shared: { + fields: { a: { type: "string" } }, + disableMigration: true, + }, + }, + }, + { + id: "b", + schema: { + shared: { + fields: { b: { type: "string" } }, + }, + }, + }, + ], + }); + + expect(tables.shared!.disableMigrations).toBe(true); + }); });