drizzle-team / drizzle-team/drizzle-orm
[FEATURE]: Please add Drizzle Kit support for discovering schema objects exported from schema files.
- Dominant language
- TypeScript
- Stars
- 35.8k
- Forks
- 1.6k
- Avg merge
- 2d 7h
- Merged PRs (30d)
- 4
Description
### Feature hasn't been suggested before.
- [x] I have verified this feature I'm about to request hasn't been suggested before.
### Describe the enhancement you want to request
right now if you want your schemas to be picked up by drizzle kit, it appears they need to be directly exported in a file drizzle kit is using. This works fine for smaller projects, but has the disadvantage of being impossible to programatically compile the list of files.
I am hoping it would be possible to export const schema, and consequently be able to put my tables into that object.. This would allow me to programatically generate my list of tables which would make my job a whole lot easier.
If helpful, here is a prompt:
Current behavior:
Drizzle Kit imports/executes each schema file matched by the `schema` config, then scans the module’s direct exported values. In `drizzle-kit/src/serializer/pgImports.ts`, `prepareFromExports()` does a shallow `Object.values(exports)` scan and collects values that are directly `PgTable`, `PgEnum`, `PgSchema`, views, sequences, roles, policies, etc.
Requested behavior:
Keep all existing top-level export behavior, but also collect Drizzle schema entities nested inside exported plain objects, so this works for migration generation:
```ts
export const users = pgTable("users", ...);
const posts = pgTable("posts", ...);
export const schema = {
users,
posts,
};
Expected result:
Both users and posts should be discovered. If a table is exported both top-level and inside schema, it should be deduped and only processed once.
Important constraints:
This should be backward-compatible.
Do not require users to name the object schema unless there is a strong reason. Prefer walking exported plain object containers generally, but avoid unsafe traversal.
Add cycle protection with a WeakSet.
Avoid traversing arbitrary non-plain objects deeply. The collector should recognize Drizzle entities first, then recurse only into arrays and plain objects.
Do not recurse into Drizzle table instances, columns, SQL objects, functions, classes, dates, etc.
Apply the same behavior consistently across dialect serializers where relevant: Postgres, MySQL, SQLite, and SingleStore.
Preserve existing collection of enums, schemas, sequences, views, materialized views, roles, and policies for Postgres.
Add tests in drizzle-kit showing nested exported schema objects are discovered.
Include a test where the same table appears top-level and nested, confirming deduping.
Include a test with a self-referential/cyclic object to confirm no crash.
Update docs if schema files are documented as only top-level exports.
Suggested implementation shape:
Create a small shared collector helper used by dialect import serializers. It should accept exported module values and dialect-specific entity matchers, then walk values safely.
Pseudo-code:
function collectFromExports(exports, matchers) {
const found = createEmptyDialectResult();
const seenObjects = new WeakSet();
const seenEntities = new Set();
function visit(value: unknown) {
if (!value || typeof value !== "object") {
return;
}
for (const matcher of matchers) {
const matchedKind = matcher(value);
if (matchedKind) {
if (!seenEntities.has(value)) {
seenEntities.add(value);
found[matchedKind].push(value);
}
return;
}
}
if (seenObjects.has(value)) {
return;
}
if (Array.isArray(value)) {
seenObjects.add(value);
value.forEach(visit);
return;
}
if (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null) {
seenObjects.add(value);
Object.values(value).forEach(visit);
}
}
Object.values(exports).forEach(visit);
return found;
}
Please make the final code fit the existing Drizzle Kit style and test structure.
I’d include a short note before the prompt if you post it to an issue/discussion:
```text
Use case: framework/tooling authors often aggregate module-owned tables into one exported schema object. Drizzle ORM runtime accepts schema objects, but Drizzle Kit migration generation currently requires each table to be top-level exported. This feature would let frameworks expose one generated/aggregated schema object without duplicating top-level export registration.
Please add Drizzle Kit support for discovering schema objects exported from schema files.
Current behavior:
Drizzle Kit imports/executes each schema file matched by the `schema` config, then scans the module’s direct exported values. In `drizzle-kit/src/serializer/pgImports.ts`, `prepareFromExports()` does a shallow `Object.values(exports)` scan and collects values that are directly `PgTable`, `PgEnum`, `PgSchema`, views, sequences, roles, policies, etc.
Requested behavior:
Keep all existing top-level export behavior, but also collect Drizzle schema entities nested inside exported plain objects, so this works for migration generation:
```ts
export const users = pgTable("users", ...);
const posts = pgTable("posts", ...);
export const schema = {
users,
posts,
};
Expected result:
Both users and posts should be discovered. If a table is exported both top-level and inside schema, it should be deduped and only processed once.
Important constraints:
This should be backward-compatible.
Do not require users to name the object schema unless there is a strong reason. Prefer walking exported plain object containers generally, but avoid unsafe traversal.
Add cycle protection with a WeakSet.
Avoid traversing arbitrary non-plain objects deeply. The collector should recognize Drizzle entities first, then recurse only into arrays and plain objects.
Do not recurse into Drizzle table instances, columns, SQL objects, functions, classes, dates, etc.
Apply the same behavior consistently across dialect serializers where relevant: Postgres, MySQL, SQLite, and SingleStore.
Preserve existing collection of enums, schemas, sequences, views, materialized views, roles, and policies for Postgres.
Add tests in drizzle-kit showing nested exported schema objects are discovered.
Include a test where the same table appears top-level and nested, confirming deduping.
Include a test with a self-referential/cyclic object to confirm no crash.
Update docs if schema files are documented as only top-level exports.
Suggested implementation shape:
Create a small shared collector helper used by dialect import serializers. It should accept exported module values and dialect-specific entity matchers, then walk values safely.
Pseudo-code:
function collectFromExports(exports, matchers) {
const found = createEmptyDialectResult();
const seenObjects = new WeakSet();
const seenEntities = new Set();
function visit(value: unknown) {
if (!value || typeof value !== "object") {
return;
}
for (const matcher of matchers) {
const matchedKind = matcher(value);
if (matchedKind) {
if (!seenEntities.has(value)) {
seenEntities.add(value);
found[matchedKind].push(value);
}
return;
}
}
if (seenObjects.has(value)) {
return;
}
if (Array.isArray(value)) {
seenObjects.add(value);
value.forEach(visit);
return;
}
if (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null) {
seenObjects.add(value);
Object.values(value).forEach(visit);
}
}
Object.values(exports).forEach(visit);
return found;
}
Please make the final code fit the existing Drizzle Kit style and test structure.
I’d include a short note before the prompt if you post it to an issue/discussion:
```text
Use case: framework/tooling authors often aggregate module-owned tables into one exported schema object. Drizzle ORM runtime accepts schema objects, but Drizzle Kit migration generation currently requires each table to be top-level exported. This feature would let frameworks expose one generated/aggregated schema object without duplicating top-level export registration.
Please add Drizzle Kit support for discovering schema objects exported from schema files.
Current behavior:
Drizzle Kit imports/executes each schema file matched by the `schema` config, then scans the module’s direct exported values. In `drizzle-kit/src/serializer/pgImports.ts`, `prepareFromExports()` does a shallow `Object.values(exports)` scan and collects values that are directly `PgTable`, `PgEnum`, `PgSchema`, views, sequences, roles, policies, etc.
Requested behavior:
Keep all existing top-level export behavior, but also collect Drizzle schema entities nested inside exported plain objects, so this works for migration generation:
```ts
export const users = pgTable("users", ...);
const posts = pgTable("posts", ...);
export const schema = {
users,
posts,
};
Expected result:
Both users and posts should be discovered. If a table is exported both top-level and inside schema, it should be deduped and only processed once.
Important constraints:
This should be backward-compatible.
Do not require users to name the object schema unless there is a strong reason. Prefer walking exported plain object containers generally, but avoid unsafe traversal.
Add cycle protection with a WeakSet.
Avoid traversing arbitrary non-plain objects deeply. The collector should recognize Drizzle entities first, then recurse only into arrays and plain objects.
Do not recurse into Drizzle table instances, columns, SQL objects, functions, classes, dates, etc.
Apply the same behavior consistently across dialect serializers where relevant: Postgres, MySQL, SQLite, and SingleStore.
Preserve existing collection of enums, schemas, sequences, views, materialized views, roles, and policies for Postgres.
Add tests in drizzle-kit showing nested exported schema objects are discovered.
Include a test where the same table appears top-level and nested, confirming deduping.
Include a test with a self-referential/cyclic object to confirm no crash.
Update docs if schema files are documented as only top-level exports.
Suggested implementation shape:
Create a small shared collector helper used by dialect import serializers. It should accept exported module values and dialect-specific entity matchers, then walk values safely.
Pseudo-code:
function collectFromExports(exports, matchers) {
const found = createEmptyDialectResult();
const seenObjects = new WeakSet();
const seenEntities = new Set();
function visit(value: unknown) {
if (!value || typeof value !== "object") {
return;
}
for (const matcher of matchers) {
const matchedKind = matcher(value);
if (matchedKind) {
if (!seenEntities.has(value)) {
seenEntities.add(value);
found[matchedKind].push(value);
}
return;
}
}
if (seenObjects.has(value)) {
return;
}
if (Array.isArray(value)) {
seenObjects.add(value);
value.forEach(visit);
return;
}
if (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null) {
seenObjects.add(value);
Object.values(value).forEach(visit);
}
}
Object.values(exports).forEach(visit);
return found;
}
Please make the final code fit the existing Drizzle Kit style and test structure.
I’d include a short note before the prompt if you post it to an issue/discussion:
```text
Use case: framework/tooling authors often aggregate module-owned tables into one exported schema object. Drizzle ORM runtime accepts schema objects, but Drizzle Kit migration generation currently requires each table to be top-level exported. This feature would let frameworks expose one generated/aggregated schema object without duplicating top-level export registration.
## Feature Request: Discover Tables Inside Exported Schema Objects
### Use Case
Framework/tooling authors often aggregate module-owned tables into one exported schema object. Drizzle ORM runtime can use schema objects, but Drizzle Kit migration generation currently requires each table to be exported at the top level.
This makes framework-generated schemas awkward because the same table list often has to be registered twice:
```ts
export const users = pgTable("users", ...);
export const posts = pgTable("posts", ...);
export const schema = {
users,
posts,
};
Contributor guide
Assessment
This issue has not been assessed yet.