Relevant source files
The following files were used as context for generating this wiki page:
- drizzle-orm/src/pg-core/dialect.ts
- drizzle-orm/src/gel-core/dialect.ts
- drizzle-orm/src/pg-core/query-builders/insert.ts
- drizzle-orm/type-tests/pg/tables.ts
- drizzle-orm/src/pg-core/query-builders/refresh-materialized-view.ts
- drizzle-orm/src/sqlite-core/dialect.ts
- drizzle-orm/src/singlestore-core/dialect.ts
- drizzle-orm/src/gel-core/query-builders/refresh-materialized-view.ts
- drizzle-orm/src/mysql-core/dialect.ts
- drizzle-orm/src/pg-core/query-builders/update.ts
- drizzle-orm/src/pg-core/db.ts
- drizzle-orm/src/sqlite-core/query-builders/insert.ts
- drizzle-orm/src/gel-core/query-builders/insert.ts
- drizzle-orm/src/pg-core/query-builders/query.ts
- drizzle-orm/src/pg-core/query-builders/index.ts
- drizzle-orm/src/pg-core/query-builders/select.ts
- drizzle-orm/src/singlestore-core/query-builders/insert.ts
- drizzle-orm/src/pg-core/view.ts
- drizzle-orm/src/pg-core/query-builders/delete.ts
- drizzle-orm/type-tests/sqlite/insert.ts
- drizzle-orm/type-tests/pg/insert.ts
- drizzle-orm/src/gel-core/query-builders/index.ts
- drizzle-orm/src/gel-core/db.ts
- drizzle-orm/src/gel-core/query-builders/select.ts
- drizzle-orm/src/gel-core/query-builders/update.ts
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