Skip to main content
doc0blade47/drizzle-ormdocumentation home
Sign in

Dialects And Schema Query Builders

Last updated Oct 12, 2026100% grounded
Relevant source files

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

Overview

The Drizzle ORM query building architecture relies on dialect-specific compiler components coupled with fluent query builder classes to transform high-level method chains into parameterized SQL AST fragments. Each database dialect (PostgreSQL, Gel, SQLite, MySQL, and SingleStore) provides its own dialect driver class that manages identifier escaping, parameter formatting, casing cache transformations, and clause assembly for insert, update, delete, and select operations.

Sources: drizzle-orm/src/pg-core/dialect.ts:609-618

Sources: drizzle-orm/src/sqlite-core/dialect.ts:596-604


Gel Query Builders

The Gel query builder subsystem shares architectural lineages with PostgreSQL-core query builders, utilizing GelDialect, GelInsertBase, GelSelectBase, and GelUpdateBase to compile queries targeting Gel databases. Insert configurations handle column filtering via col.shouldDisableInsert(), fallback to column default functions (col.defaultFn) or onUpdateFn, and compile returning and on conflict clauses when present.

Sources: drizzle-orm/src/gel-core/dialect.ts:508-575

const inserted = await db.insert(users)
  .values({ name: 'Gel User' })
  .returning();

Sources: drizzle-orm/src/gel-core/query-builders/insert.ts:220-279

The Gel selection framework leverages GelSelectBuilder and GelSelectQueryBuilderBase to manage complex relation projections, join configurations, and set operators (union, intersect, except) with strict key validation checks.

Sources: drizzle-orm/src/gel-core/query-builders/select.ts:60-145

Note

Gel query builder methods validate set operator compatibility by inspecting whether left and right selection keys match identically and maintain the same order.

Sources: drizzle-orm/src/gel-core/query-builders/select.ts:515-520

if (!haveSameKeys((leftSelect as any).getSelectedFields(), setOperator.rightSelect.getSelectedFields())) {
    throw new Error(
        'Set operator error (union / intersect / except): selected fields are not the same or are in a different order',
    );
}

Sources: drizzle-orm/src/gel-core/query-builders/select.ts:1119-1125


MySQL Query Builders

MySQL-core query compilation is managed by MySqlDialect alongside MySqlInsertConfig and related query builders. When compiling insert queries via buildInsertQuery, the dialect filters out insert-disabled columns and iterates over input value records.

Sources: drizzle-orm/src/mysql-core/dialect.ts:561-567

	buildInsertQuery({
		table,
		values: valuesOrSelect,
		ignore,
		onConflict,
		select,
	}: MySqlInsertConfig): { sql: SQL; generatedIds: Record<string, unknown>[] } {

Sources: drizzle-orm/src/mysql-core/dialect.ts:561-567

For each column entry during an insert operation, if a field value is undefined or an unassigned Param, the dialect checks column defaults (col.defaultFn) or update functions (col.onUpdateFn), populates generated ID tracking dictionaries, and constructs ignore and on duplicate key clauses.

Sources: drizzle-orm/src/mysql-core/dialect.ts:586-645

Important

MySQL does not support a native do nothing conflict clause directly; developers achieve this behavior by setting a unique column to its own value (e.g., { id: sqlid }) within .onDuplicateKeyUpdate().

Sources: drizzle-orm/src/singlestore-core/query-builders/insert.ts:246-253

	onDuplicateKeyUpdate(
		config: SingleStoreInsertOnDuplicateKeyUpdateConfig<this>,
	): SingleStoreInsertWithout<this, TDynamic, 'onDuplicateKeyUpdate'> {
		const setSql = this.dialect.buildUpdateSet(this.config.table, mapUpdateSet(this.config.table, config.set));
		this.config.onConflict = sql`update ${setSql}`;
		return this as any;
	}

Sources: drizzle-orm/src/singlestore-core/query-builders/insert.ts:246-253


PostgreSQL Query Builders

PostgreSQL dialect compilation (PgDialect) drives advanced clause generation including CTEs (withList), column casing identifiers, system value overrides (overriding system value), and conflict resolution.

Sources: drizzle-orm/src/pg-core/dialect.ts:513-515

	buildInsertQuery(
		{ table, values: valuesOrSelect, onConflict, returning, withList, select, overridingSystemValue_ }: PgInsertConfig,
	): SQL {

Sources: drizzle-orm/src/pg-core/dialect.ts:513-515

The PgInsertBase class provides conflict handling methods .onConflictDoNothing() and .onConflictDoUpdate().

Sources: drizzle-orm/src/pg-core/query-builders/insert.ts:369-389

	onConflictDoUpdate(
		config: PgInsertOnConflictDoUpdateConfig<this>,
	): PgInsertWithout<this, TDynamic, 'onConflictDoNothing' | 'onConflictDoUpdate'> {
		if (config.where && (config.targetWhere || config.setWhere)) {
			throw new Error(
				'You cannot use both "where" and "targetWhere"/"setWhere" at the same time - "where" is deprecated, use "targetWhere" or "setWhere" instead.',
			);
		}
		const whereSql = config.where ? sql` where ${config.where}` : undefined;
		const targetWhereSql = config.targetWhere ? sql` where ${config.targetWhere}` : undefined;
		const setWhereSql = config.setWhere ? sql` where ${config.setWhere}` : undefined;
		const setSql = this.dialect.buildUpdateSet(this.config.table, mapUpdateSet(this.config.table, config.set));
		let targetColumn = '';
		targetColumn = Array.isArray(config.target)
			? config.target.map((it) => this.dialect.escapeName(this.dialect.casing.getColumnCasing(it))).join(',')
			: this.dialect.escapeName(this.dialect.casing.getColumnCasing(config.target));
		this.config.onConflict = sql`(${
			sql.raw(targetColumn)
		})${targetWhereSql} do update set ${setSql}${whereSql}${setWhereSql}`;
		return this as any;
	}

Sources: drizzle-orm/src/pg-core/query-builders/insert.ts:369-389

PostgreSQL views and materialized views support execution refreshing via PgRefreshMaterializedView.

Sources: drizzle-orm/src/pg-core/query-builders/refresh-materialized-view.ts:30-65

export class PgRefreshMaterializedView<TQueryResult extends PgQueryResultHKT>
	extends QueryPromise<PgQueryResultKind<TQueryResult, never>>
	implements RunnableQuery<PgQueryResultKind<TQueryResult, never>, 'pg'>, SQLWrapper
{
	static override readonly [entityKind]: string = 'PgRefreshMaterializedView';
 
	private config: {
		view: PgMaterializedView;
		concurrently?: boolean;
		withNoData?: boolean;
	};
 
	constructor(
		view: PgMaterializedView,
		private session: PgSession,
		private dialect: PgDialect,
	) {
		super();
		this.config = { view };
	}
 
	concurrently(): this {
		if (this.config.withNoData !== undefined) {
			throw new Error('Cannot use concurrently and withNoData together');
		}
		this.config.concurrently = true;
		return this;
	}
 
	withNoData(): this {
		if (this.config.concurrently !== undefined) {
			throw new Error('Cannot use concurrently and withNoData together');
		}
		this.config.withNoData = true;
		return this;
	}

Sources: drizzle-orm/src/pg-core/query-builders/refresh-materialized-view.ts:30-65

Caution

Attempting to combine .concurrently() and .withNoData() on a materialized view refresh triggers an explicit error invariant check in both PostgreSQL and Gel implementations.

Sources: drizzle-orm/src/pg-core/query-builders/refresh-materialized-view.ts:51-54

if (this.config.withNoData !== undefined) {
    throw new Error('Cannot use concurrently and withNoData together');
}

Sources: drizzle-orm/src/pg-core/query-builders/refresh-materialized-view.ts:51-54


SingleStore Query Builders

SingleStore query building is directed by SingleStoreDialect and SingleStoreInsertBase. The dialect handles migration bootstrapping by verifying and creating the __drizzle_migrations table via session.execute(), and executes insert queries supporting ignore flags and duplicate key updates.

Sources: drizzle-orm/src/singlestore-core/dialect.ts:53-66

	buildInsertQuery({
		table,
		values,
		ignore,
		onConflict,
	}: SingleStoreInsertConfig): {
		sql: SQL;
		generatedIds: Record<string, unknown>[];
	} {

Sources: drizzle-orm/src/singlestore-core/dialect.ts:519-527

When executing inserts, SingleStore tracks primary key auto-increment columns to generate response IDs, formatting clauses with on duplicate key update.

Sources: drizzle-orm/src/singlestore-core/query-builders/insert.ts:246-253

	onDuplicateKeyUpdate(
		config: SingleStoreInsertOnDuplicateKeyUpdateConfig<this>,
	): SingleStoreInsertWithout<this, TDynamic, 'onDuplicateKeyUpdate'> {
		const setSql = this.dialect.buildUpdateSet(this.config.table, mapUpdateSet(this.config.table, config.set));
		this.config.onConflict = sql`update ${setSql}`;
		return this as any;
	}

Sources: drizzle-orm/src/singlestore-core/query-builders/insert.ts:246-253


SQLite Query Builders

SQLite query compilation (SQLiteDialect) manages parameter formatting (?), string escaping (escapeString), and identifier quoting (escapeName).

Sources: drizzle-orm/src/sqlite-core/dialect.ts:57-67

	escapeName(name: string): string {
		return `"${name.replace(/"/g, '""')}"`;
	}
 
	escapeParam(_num: number): string {
		return '?';
	}
 
	escapeString(str: string): string {
		return `'${str.replace(/'/g, "''")}'`;
	}

Sources: drizzle-orm/src/sqlite-core/dialect.ts:57-67

The SQLiteInsertBase builder handles table insertion records, falling back to column defaults or null values when parameters are omitted, and supports .returning() and .onConflictDoNothing() / .onConflictDoUpdate() clauses.

Sources: drizzle-orm/src/sqlite-core/query-builders/insert.ts:306-317

	onConflictDoNothing(config: { target?: IndexColumn | IndexColumn[]; where?: SQL } = {}): this {
		if (!this.config.onConflict) this.config.onConflict = [];
 
		if (config.target === undefined) {
			this.config.onConflict.push(sql` on conflict do nothing`);
		} else {
			const targetSql = Array.isArray(config.target) ? sql`${config.target}` : sql`${[config.target]}`;
			const whereSql = config.where ? sql` where ${config.where}` : sql``;
			this.config.onConflict.push(sql` on conflict ${targetSql} do nothing${whereSql}`);
		}
		return this;
	}

Sources: drizzle-orm/src/sqlite-core/query-builders/insert.ts:306-317

Was this page helpful?