---
title: "Database Introspection"
description: "Database introspection in Drizzle Kit recovers relational database schemas from live database instances across multiple supported dialects, normalizing catalog metadata into structured JSON migrati..."
last_updated: "2026-10-12T08:14:00.734142+00:00"
canonical_url: "https://www.doc0.dev/docs/e1b68fed-3c4e-4c95-b2ba-ebf050f78025/technical/migration-toolkit/database-introspection"
---

<details>
<summary>Relevant source files</summary>

The following files were used as context for generating this wiki page:

- [drizzle-kit/src/introspect-singlestore.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-singlestore.ts)
- [drizzle-kit/src/introspect-mysql.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-mysql.ts)
- [drizzle-kit/src/cli/commands/introspect.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/cli/commands/introspect.ts)
- [drizzle-kit/src/api.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/api.ts)
- [drizzle-kit/src/cli/schema.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/cli/schema.ts)
- [drizzle-kit/src/serializer/singlestoreSerializer.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/serializer/singlestoreSerializer.ts)
- [drizzle-kit/src/serializer/gelSerializer.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/serializer/gelSerializer.ts)
- [drizzle-kit/src/serializer/studio.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/serializer/studio.ts)
- [drizzle-kit/src/introspect-pg.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-pg.ts)
- [drizzle-kit/src/cli/commands/sqliteIntrospect.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/cli/commands/sqliteIntrospect.ts)
- [drizzle-kit/src/introspect-gel.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-gel.ts)
- [drizzle-kit/src/serializer/mysqlSerializer.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/serializer/mysqlSerializer.ts)
- [drizzle-kit/src/introspect-sqlite.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-sqlite.ts)
- [drizzle-kit/src/serializer/pgSerializer.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/serializer/pgSerializer.ts)
- [drizzle-kit/src/cli/commands/mysqlIntrospect.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/cli/commands/mysqlIntrospect.ts)
- [drizzle-kit/src/sqlgenerator.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/sqlgenerator.ts)
- [drizzle-kit/src/cli/commands/singlestoreIntrospect.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/cli/commands/singlestoreIntrospect.ts)
- [drizzle-kit/src/serializer/sqliteSerializer.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/serializer/sqliteSerializer.ts)
- [drizzle-kit/src/serializer/mysqlSchema.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/serializer/mysqlSchema.ts)
- [integration-tests/drizzle2/planetscale/meta/0000_snapshot.json](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/integration-tests/drizzle2/planetscale/meta/0000_snapshot.json)
- [integration-tests/drizzle2/mysql/meta/0000_snapshot.json](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/integration-tests/drizzle2/mysql/meta/0000_snapshot.json)
- [integration-tests/drizzle2/singlestore/meta/0000_snapshot.json](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/integration-tests/drizzle2/singlestore/meta/0000_snapshot.json)
- [drizzle-kit/src/cli/commands/pgIntrospect.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/cli/commands/pgIntrospect.ts)
- [integration-tests/drizzle2/pg/meta/0000_snapshot.json](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/integration-tests/drizzle2/pg/meta/0000_snapshot.json)
- [integration-tests/drizzle2/mysql-proxy/first/meta/0000_snapshot.json](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/integration-tests/drizzle2/mysql-proxy/first/meta/0000_snapshot.json)
</details>

## Overview

Database introspection in Drizzle Kit recovers relational database schemas from live database instances across multiple supported dialects, normalizing catalog metadata into structured JSON migration snapshots and translating them into idiomatic Drizzle TypeScript schema definitions.

Sources: [drizzle-kit/src/cli/schema.ts:538-623](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/cli/schema.ts#L538-L623), [drizzle-kit/src/serializer/singlestoreSerializer.ts:400-411](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/serializer/singlestoreSerializer.ts#L400-L411), and [drizzle-kit/src/serializer/mysqlSerializer.ts:564-573](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/serializer/mysqlSerializer.ts#L564-L573)

## CLI Introspection Orchestration

### Dialect Dispatch and Driver Checks

The CLI command handler for introspection ensures output directories are created recursively via `mkdirSync(out, { recursive: true })` and evaluates dialect branches to dynamically import and invoke dialect-specific introspection routines. For PostgreSQL credentials carrying a specific driver option, version compatibility checks against `drizzle-orm` are enforced before proceeding.

| Dialect | Credential Type | Introspection Function | Target Module File |
| :--- | :--- | :--- | :--- |
| `postgresql` | `PostgresCredentials` | `introspectPostgres` | `drizzle-kit/src/cli/commands/introspect.ts` |
| `mysql` | `MysqlCredentials` | `introspectMysql` | `drizzle-kit/src/cli/commands/introspect.ts` |
| `sqlite` | `SqliteCredentials` | `introspectSqlite` | `drizzle-kit/src/cli/commands/introspect.ts` |
| `turso` | `LibSQLCredentials` | `introspectLibSQL` | `drizzle-kit/src/cli/commands/introspect.ts` |
| `singlestore` | `SingleStoreCredentials` | `introspectSingleStore` | `drizzle-kit/src/cli/commands/introspect.ts` |
| `gel` | `GelCredentials` | `introspectGel` | `drizzle-kit/src/cli/commands/introspect.ts` |

> [!WARNING]
> When executing PostgreSQL introspection with the `aws-data-api` driver, `drizzle-orm` version `0.30.10` or higher is strictly required; using `pglite` requires version `0.30.6` or higher. Failing this check terminates the process with exit code `1`.

Sources: [drizzle-kit/src/cli/schema.ts:524-625](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/cli/schema.ts#L524-L625)

### Filtering and Progress Reporting

Table filtering is implemented across database dialects by mapping each provided table filter string into a `Minimatch` instance. The filter function evaluates table names against all matchers, taking negation patterns into account and enforcing that all match criteria pass via `flags.every(Boolean)`.

```typescript
const matchers = tablesFilter.map((it) => {
	return new Minimatch(it);
});

const filter = (tableName: string) => {
	if (matchers.length === 0) return true;

	let flags: boolean[] = [];

	for (let matcher of matchers) {
		if (matcher.negate) {
			if (!matcher.match(tableName)) {
				flags.push(false);
			}
		}

		if (matcher.match(tableName)) {
			flags.push(true);
		}
	}

	if (flags.length > 0) {
		return flags.every(Boolean);
	}
	return false;
};
```

Progress reporting runs concurrently with database extraction by instantiating an `IntrospectProgress` reporter and wrapping the database fetch task with `renderWithTask`, where status updates propagate stage, count, and status arguments down to `progress.update(stage, count, status)`.

Sources: [drizzle-kit/src/cli/commands/introspect.ts:184-234](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/cli/commands/introspect.ts#L184-L234), [drizzle-kit/src/cli/commands/introspect.ts:318-351](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/cli/commands/introspect.ts#L318-L351)

### Snapshot Diffing and Output Generation

Once schema objects are retrieved from the database and converted into TypeScript files (`schema.ts` and `relations.ts`), migration folders are inspected via `prepareOutFolder(out, dialect)`. If no existing snapshots are detected (`snapshots.length === 0`), dialect-specific snapshot diff functions compute SQL migration statements and metadata.

```typescript
const { snapshots, journal } = prepareOutFolder(out, 'mysql');

if (snapshots.length === 0) {
	const { sqlStatements, _meta } = await applyMysqlSnapshotsDiff(
		squashMysqlScheme(dryMySql),
		squashMysqlScheme(schema),
		tablesResolver,
		columnsResolver,
		mySqlViewsResolver,
		dryMySql,
		schema,
	);

	writeResult({
		cur: schema,
		sqlStatements,
		journal,
		_meta,
		outFolder: out,
		breakpoints,
		type: 'introspect',
		prefixMode: prefix,
	});
} else {
	render(
		`[${
			chalk.blue(
				'i',
			)
		}] No SQL generated, you already have migrations in project`,
	);
}
```

> [!NOTE]
> If snapshot files already exist inside the project output folder, introspection skips generating new migration SQL and outputs an informational message indicating that migrations are already present.

Sources: [drizzle-kit/src/cli/commands/introspect.ts:364-395](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/cli/commands/introspect.ts#L364-L395)

## PostgreSQL Catalog Inspection

### PostgreSQL Introspection and Push Execution

PostgreSQL schema introspection is driven through `pgPushIntrospect`, which processes user-supplied table filter strings into `Minimatch` instances to evaluate and filter table names against positive and negative match criteria.

```typescript
const matchers = filters.map((it) => {
	return new Minimatch(it);
});

const filter = (tableName: string) => {
	if (matchers.length === 0) return true;

	let flags: boolean[] = [];

	for (let matcher of matchers) {
		if (matcher.negate) {
			if (!matcher.match(tableName)) {
				flags.push(false);
			}
		}

		if (matcher.match(tableName)) {
			flags.push(true);
		}
	}

	if (flags.length > 0) {
		return flags.every(Boolean);
	}
	return false;
};
```
Sources: [drizzle-kit/src/cli/commands/pgIntrospect.ts:17-42](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/cli/commands/pgIntrospect.ts#L17-L42)

The introspection execution wraps schema pulling within a terminal progress view using `renderWithTask` before appending internal identifiers to construct the final serialized `PgSchema` payload.

```typescript
	const progress = new ProgressView(
		'Pulling schema from database...',
		'Pulling schema from database...',
	);
	const res = await renderWithTask(
		progress,
		fromDatabase(db, filter, schemaFilters, entities, undefined, tsSchema),
	);

	const schema = { id: originUUID, prevId: '', ...res } as PgSchema;
	const { internal, ...schemaWithoutInternals } = schema;
	return { schema: schemaWithoutInternals };
```
Sources: [drizzle-kit/src/cli/commands/pgIntrospect.ts:43-54](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/cli/commands/pgIntrospect.ts#L43-L54)

### Catalog Transformation and TypeScript Generation

Catalog reconstruction inspects database entities, mapping identities, sequences, columns, roles, and schema definitions into corresponding TypeScript constructs. When reconstructing column identities, parameters such as `maxValue`, `cache`, and `cycle` are serialized into `.generatedAlwaysAsIdentity()` or `.generatedByDefaultAsIdentity()` calls.

```typescript
	if (identity?.maxValue) {
		paramsObj += `, maxValue: ${identity.maxValue}`;
	}
	if (identity?.cache) {
		paramsObj += `, cache: ${identity.cache}`;
	}
	if (identity?.cycle) {
		paramsObj += `, cycle: true`;
	}
	paramsObj += ' }';
	if (identity?.type === 'always') {
		return `.generatedAlwaysAsIdentity(${paramsObj})`;
	}
	return `.generatedByDefaultAsIdentity(${paramsObj})`;
```
Sources: [drizzle-kit/src/introspect-pg.ts:289-302](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-pg.ts#L289-L302)

> [!NOTE]
> Parameter name generation uses `paramNameFor`, appending a capitalised schema suffix when a non-public schema is present to avoid name collisions across distinct PostgreSQL schemas.

Sources: [drizzle-kit/src/introspect-pg.ts:304-307](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-pg.ts#L304-L307)

## MySQL and SingleStore Schema Recovery

### Introspection Commands and Table Filtering

MySQL and SingleStore schema introspection processes database metadata by executing database pulls through `mysqlPushIntrospect` and `singlestorePushIntrospect`. Both routines accept database connection handles, target database names, and filter arrays to construct `Minimatch` instances that selectively include or exclude tables based on pattern matching rules and negated match flags.

```typescript
	const matchers = filters.map((it) => {
		return new Minimatch(it);
	});

	const filter = (tableName: string) => {
		if (matchers.length === 0) return true;

		let flags: boolean[] = [];

		for (let matcher of matchers) {
			if (matcher.negate) {
				if (!matcher.match(tableName)) {
					flags.push(false);
				}
			}

			if (matcher.match(tableName)) {
				flags.push(true);
			}
		}

		if (flags.length > 0) {
			return flags.every(Boolean);
		}
		return false;
	};
```
Sources: [drizzle-kit/src/cli/commands/mysqlIntrospect.ts:14-39](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/cli/commands/mysqlIntrospect.ts#L14-L39), [drizzle-kit/src/cli/commands/singlestoreIntrospect.ts:14-39](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/cli/commands/singlestoreIntrospect.ts#L14-L39)

> [!NOTE]
> During push introspection, the `ProgressView` utility renders a terminal task indicator labeled `'Pulling schema from database...'` while `fromDatabase` queries catalog tables.

Sources: [drizzle-kit/src/cli/commands/mysqlIntrospect.ts:41-48](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/cli/commands/mysqlIntrospect.ts#L41-L48), [drizzle-kit/src/cli/commands/singlestoreIntrospect.ts:41-48](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/cli/commands/singlestoreIntrospect.ts#L41-L48)

### Casing Transformation and Schema Squashing

Field names and identifiers undergo casing transformation determined by the active casing configuration. The `prepareCasing` helper checks whether casing is set to `'preserve'` or `'camel'`, routing column keys through `escapeColumnKey` or string transformation methods.

```typescript
const escapeColumnKey = (value: string) => {
	if (/^(?![a-zA-Z_$][a-zA-Z0-9_$]*$).+$/.test(value)) {
		return `"${value}"`;
	}
	return value;
};

const prepareCasing = (casing?: Casing) => (value: string) => {
	if (casing === 'preserve') {
		return escapeColumnKey(value);
	}
	if (casing === 'camel') {
		return escapeColumnKey(value.camelCase());
	}

	assertUnreachable(casing);
};
```
Sources: [drizzle-kit/src/introspect-mysql.ts:104-120](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-mysql.ts#L104-L120), [drizzle-kit/src/introspect-singlestore.ts:110-126](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-singlestore.ts#L110-L126)

Catalog serialization and migration diffing rely on squasher functions defined in `mysqlSchema.ts`. The squasher flattens indices, foreign keys, primary keys, unique constraints, check constraints, and views into delimited string representations for snapshot comparison.

| Squasher Method | Serialized Components | Source Reference |
| :--- | :--- | :--- |
| `squashIdx` | `name`, `columns`, `isUnique`, `using`, `algorithm`, `lock` | [drizzle-kit/src/serializer/mysqlSchema.ts:223-228](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/serializer/mysqlSchema.ts#L223-L228) |
| `squashPK` | `name`, `columns` | [drizzle-kit/src/serializer/mysqlSchema.ts:241-243](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/serializer/mysqlSchema.ts#L241-L243) |
| `squashUnique` | `name`, `columns` | [drizzle-kit/src/serializer/mysqlSchema.ts:248-250](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/serializer/mysqlSchema.ts#L248-L250) |
| `squashFK` | `name`, `tableFrom`, `columnsFrom`, `tableTo`, `columnsTo`, `onUpdate`, `onDelete` | [drizzle-kit/src/serializer/mysqlSchema.ts:255-259](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/serializer/mysqlSchema.ts#L255-L259) |
| `squashCheck` | `name`, `value` | [drizzle-kit/src/serializer/mysqlSchema.ts:282-284](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/serializer/mysqlSchema.ts#L282-L284) |
| `squashView` | `algorithm`, `sqlSecurity`, `withCheckOption` | [drizzle-kit/src/serializer/mysqlSchema.ts:290-292](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/serializer/mysqlSchema.ts#L290-L292) |

Sources: [drizzle-kit/src/serializer/mysqlSchema.ts:223-292](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/serializer/mysqlSchema.ts#L223-L292)

> [!WARNING]
> In MySQL schemas, text and tinytext columns cannot have default values assigned; introspection guards against unsupported defaults when mapping column properties.

Sources: [drizzle-kit/src/introspect-mysql.ts:602-609](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-mysql.ts#L602-L609)

## SQLite Catalog Recovery

### Table Filtering and Introspection Execution

The SQLite introspection pipeline connects to live SQLite and LibSQL databases using configured credentials, applying glob table filters via `Minimatch` before delegating schema serialization to `fromDatabase`. The `sqliteIntrospect` and `sqlitePushIntrospect` functions process filter matchers supporting negation rules, evaluating table names through an array accumulator and returning boolean conditions.

```typescript
export const sqliteIntrospect = async (
	credentials: SqliteCredentials,
	filters: string[],
	casing: Casing,
) => {
	const { connectToSQLite } = await import('../connections');
	const db = await connectToSQLite(credentials);

	const matchers = filters.map((it) => {
		return new Minimatch(it);
	});

	const filter = (tableName: string) => {
		if (matchers.length === 0) return true;

		let flags: boolean[] = [];

		for (let matcher of matchers) {
			if (matcher.negate) {
				if (!matcher.match(tableName)) {
					flags.push(false);
				}
			}

			if (matcher.match(tableName)) {
				flags.push(true);
			}
		}

		if (flags.length > 0) {
			return flags.every(Boolean);
		}
		return false;
	};

	const progress = new IntrospectProgress();
	const res = await renderWithTask(
		progress,
		fromDatabase(db, filter, (stage, count, status) => {
			progress.update(stage, count, status);
		}),
	);

	const schema = { id: originUUID, prevId: '', ...res } as SQLiteSchema;
	const ts = schemaToTypeScript(schema, casing);
	return { schema, ts };
};
```
Sources: [drizzle-kit/src/cli/commands/sqliteIntrospect.ts:12-58](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/cli/commands/sqliteIntrospect.ts#L12-L58)

> [!NOTE]
> When executing `sqlitePushIntrospect`, the CLI renders a `ProgressView` terminal task instead of interactive progress bars while querying catalog tables from the target database instance.

Sources: [drizzle-kit/src/cli/commands/sqliteIntrospect.ts:88-92](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/cli/commands/sqliteIntrospect.ts#L88-L92)

### Column Mapping and Default Value Parsing

Recovered SQLite column types map database definitions to TypeScript declarations while processing default values, column flags, and self-referential or cyclic foreign key constraints. The `mapColumnDefault` utility handles SQL expressions enclosed in parentheses, stringified `NULL` constants, and quoted string defaults by unescaping interior quotes.

```typescript
const mapColumnDefault = (defaultValue: any) => {
	if (
		typeof defaultValue === 'string'
		&& defaultValue.startsWith('(')
		&& defaultValue.endsWith(')')
	) {
		return `sql\`${defaultValue}\``;
	}
	if (defaultValue === 'NULL') {
		return `sql\`NULL\``;
	}

	if (
		typeof defaultValue === 'string'
	) {
		return defaultValue.substring(1, defaultValue.length - 1).replaceAll('"', '\\"').replaceAll("''", "'");
	}

	return defaultValue;
};
```
Sources: [drizzle-kit/src/introspect-sqlite.ts:258-278](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-sqlite.ts#L258-L278)

> [!WARNING]
> SQLite stores literal null values as the string `'NULL'` or wrapped representations in system catalogs; introspection catches these specifically to emit explicit `sql\`NULL\`` expressions.

Sources: [drizzle-kit/src/introspect-sqlite.ts:266-269](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-sqlite.ts#L266-L269)

Foreign key relationships are analyzed for self-referential structures and cyclic dependencies by checking key pairs against registered relation sets.

| Relation Helper | Condition Evaluated | Source Reference |
| :--- | :--- | :--- |
| `isCyclic` | Checks whether both `tableFrom-tableTo` and reverse `tableTo-tableFrom` exist in relations | [drizzle-kit/src/introspect-sqlite.ts:248-252](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-sqlite.ts#L248-L252) |
| `isSelf` | Verifies if `tableFrom` matches `tableTo` on the foreign key definition | [drizzle-kit/src/introspect-sqlite.ts:254-256](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-sqlite.ts#L254-L256) |

Sources: [drizzle-kit/src/introspect-sqlite.ts:248-256](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-sqlite.ts#L248-L256)

## Gel Schema Extraction

### Default Value Mapping Rules

Gel introspection maps database types, array flags, and default expression constraints into structured TypeScript declarations [Migration Toolkit Schema](https://www.doc0.dev/docs/e1b68fed-3c4e-4c95-b2ba-ebf050f78025/technical/migration-toolkit/migration-toolkit-schema). The `mapDefault` function inspects column metadata, handling type-specific formatting for integers, floating-point numbers, UUIDs, dates, durations, JSON, and byte arrays.

```typescript
const isCyclic = (fk: ForeignKey) => {
	const key = `${fk.tableFrom}-${fk.tableTo}`;
	const reverse = `${fk.tableTo}-${fk.tableFrom}`;
	return relations.has(key) && relations.has(reverse);
};

const isSelf = (fk: ForeignKey) => {
	return fk.tableFrom === fk.tableTo;
};
```
Sources: [drizzle-kit/src/introspect-gel.ts:522-530](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-gel.ts#L522-L530)

Array defaults undergo sanitization through `buildArrayDefault`, checking whether the default value string begins with `ARRAY[` or `_nullif_array_nulls(ARRAY[` before wrapping expressions in SQL template literals.

```typescript
const buildArrayDefault = (defaultValue: string, typeName: string): string => {
	if (
		typeof defaultValue === 'string'
		&& !(defaultValue.startsWith('_nullif_array_nulls(ARRAY[') || defaultValue.startsWith('ARRAY['))
	) {
		return `sql\`${defaultValue}\``;
	}

	const regex = /ARRAY\[(.*)\]/;
	const match = defaultValue.match(regex);

	if (!match) {
		return `sql\`${defaultValue}\``;
	}

	defaultValue = match[1];
	return `sql\`[${defaultValue}]\``;
};
```
Sources: [drizzle-kit/src/introspect-gel.ts:532-549](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-gel.ts#L532-L549)

> [!NOTE]
> Gel column mapping distinguishes between standard SQL types and prefixed extension types such as `edgedbt.bigint_t`, `edgedbt.date_duration_t`, `edgedbt.timestamptz_t`, `edgedbt.duration_t`, `edgedbt.date_t`, and `edgedbt.relative_duration_t`.

Sources: [drizzle-kit/src/introspect-gel.ts:596-673](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-gel.ts#L596-L673)

| Data Type Prefix / Condition | Default Evaluation Behavior | Source Reference |
| :--- | :--- | :--- |
| `name === 'id'` | Returns `.default(sql\`uuid_generate_v4()\`)` | [drizzle-kit/src/introspect-gel.ts:564-566](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-gel.ts#L564-L566) |
| `isArray` | Delegates to `buildArrayDefault` when `defaultValue` is defined | [drizzle-kit/src/introspect-gel.ts:568-570](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-gel.ts#L568-L570) |
| `edgedbt.bigint_t` | Wraps parsed column default inside `BigInt(...)` | [drizzle-kit/src/introspect-gel.ts:596-600](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-gel.ts#L596-L600) |
| `uuid` (`gen_random_uuid()`) | Emits `.defaultRandom()` | [drizzle-kit/src/introspect-gel.ts:618-620](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-gel.ts#L618-L620) |
| `edgedbt.timestamptz_t` (`now()`) | Emits `.defaultNow()` | [drizzle-kit/src/introspect-gel.ts:637-639](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-gel.ts#L637-L639) |
| `edgedbt.date_t` (`now()`) | Emits `.defaultNow()` | [drizzle-kit/src/introspect-gel.ts:661-663](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-gel.ts#L661-L663) |

Sources: [drizzle-kit/src/introspect-gel.ts:564-663](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-gel.ts#L564-L663)

> [!WARNING]
> Integer, smallint, and bigint default values strip enclosing parentheses via `.replaceAll('(', '').replaceAll(')', '')` before being passed to `mapColumnDefault`.

Sources: [drizzle-kit/src/introspect-gel.ts:578-594](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-gel.ts#L578-L594)

## TypeScript Declaration Code Generation

### Schema to TypeScript Mapping and Imports

The code generation phase inspects recovered schema structures and aggregates column types, constraints, and relational entities to emit standard Drizzle ORM TypeScript declarations. Across PostgreSQL, MySQL, SingleStore, SQLite, and Gel introspectors, builders verify dependency names and compile distinct import lists. For instance, SingleStore and MySQL generation evaluate table column types, composite primary keys, unique constraints, and indexes to construct the required core imports[Migration Toolkit Schema](https://www.doc0.dev/docs/e1b68fed-3c4e-4c95-b2ba-ebf050f78025/technical/migration-toolkit/migration-toolkit-schema). Casing configurations (`preserve` or `camel`) determine whether identifiers undergo key escaping via `prepareCasing` and `escapeColumnKey`.

```typescript
const singlestoreImportsList = new Set([
	'singlestoreTable',
	'singlestoreEnum',
	'bigint',
	'binary',
	'boolean',
	'char',
	'date',
	'datetime',
	'decimal',
	'double',
	'float',
	'int',
	'json',
	// TODO: add new type BSON
	// TODO: add new type Blob
	// TODO: add new type UUID
	// TODO: add new type GUID
	// TODO: add new type Vector
	// TODO: add new type GeoPoint
	'mediumint',
	'real',
	'serial',
	'smallint',
	'text',
	'tinytext',
	'mediumtext',
	'longtext',
	'time',
	'timestamp',
	'tinyint',
	'varbinary',
	'varchar',
	'vector',
	'year',
	'enum',
]);
```
Sources: [drizzle-kit/src/introspect-singlestore.ts:19-55](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-singlestore.ts#L19-L55)

> [!NOTE]
> When table names or column identifiers collide with reserved import tokens or require safe property syntax, `escapeColumnKey` wraps them in double quotes if they fail valid identifier regex checks.

Sources: [drizzle-kit/src/introspect-singlestore.ts:110-115](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-singlestore.ts#L110-L115), [drizzle-kit/src/introspect-mysql.ts:104-109](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-mysql.ts#L104-L109)

### Column Mapping and Default Value Formatting

Column generators translate raw data types and constraint flags into chainable Drizzle builder methods. Unsigned integer modifiers, auto-increment configurations, and default expressions are formatted through dialect-specific helper functions such as `mapColumnDefault`, `mapColumnDefaultForJson`, and `binaryConfig`.

```typescript
const mapColumnDefault = (defaultValue: any, isExpression?: boolean) => {
	if (isExpression) {
		return `sql\`${defaultValue}\``;
	}

	return defaultValue;
};

const mapColumnDefaultForJson = (defaultValue: any) => {
	if (
		typeof defaultValue === 'string'
		&& defaultValue.startsWith("('")
		&& defaultValue.endsWith("')")
	) {
		return defaultValue.substring(2, defaultValue.length - 2);
	}

	return defaultValue;
};
```
Sources: [drizzle-kit/src/introspect-singlestore.ts:341-359](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-singlestore.ts#L341-L359)

| Column Type / Dialect Helper | Behavior and Transformation | Source Reference |
| :--- | :--- | :--- |
| `serial` | Emits `serial(...)` without explicit type parameters | [drizzle-kit/src/introspect-singlestore.ts:376-378](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-singlestore.ts#L376-L378) |
| `int` (Unsigned) | Appends `{ unsigned: true }` configuration object if lowered type includes `unsigned` | [drizzle-kit/src/introspect-singlestore.ts:380-388](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-singlestore.ts#L380-L388) |
| Expression Defaults | Wraps expressions inside `sql\`...\`` via `mapColumnDefault` | [drizzle-kit/src/introspect-singlestore.ts:341-347](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-singlestore.ts#L341-L347) |
| JSON Defaults | Strips wrapping parentheses and quotes from JSON default strings via `mapColumnDefaultForJson` | [drizzle-kit/src/introspect-singlestore.ts:349-359](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-singlestore.ts#L349-L359) |

Sources: [drizzle-kit/src/introspect-singlestore.ts:341-388](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-singlestore.ts#L341-L388)

> [!WARNING]
> Cyclic foreign key relationships between tables trigger the inclusion of utility type imports like `AnyPgColumn` or specialized constraint checks to prevent circular type inference failures in generated schemas.

Sources: [drizzle-kit/src/introspect-pg.ts:333-335](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-pg.ts#L333-L335), [drizzle-kit/src/introspect-mysql.ts:156-160](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-kit/src/introspect-mysql.ts#L156-L160)

## Related

- [Migration Toolkit Schema](https://www.doc0.dev/docs/e1b68fed-3c4e-4c95-b2ba-ebf050f78025/technical/migration-toolkit/migration-toolkit-schema)
- [CLI Command Architecture](https://www.doc0.dev/docs/e1b68fed-3c4e-4c95-b2ba-ebf050f78025/technical/migration-toolkit/cli-command-architecture)


## Sitemap

See the full [sitemap](https://www.doc0.dev/docs/e1b68fed-3c4e-4c95-b2ba-ebf050f78025/llms.txt) for all pages in this wiki.
