---
title: "SQL Expressions"
description: "SQL Expressions are the fundamental building blocks of Drizzle ORM's query-building system. They provide a unified, type-safe abstraction for constructing SQL queries across different database dial..."
last_updated: "2026-08-13T14:49:36.092828+00:00"
canonical_url: "https://www.doc0.app/docs/e1b68fed-3c4e-4c95-b2ba-ebf050f78025/technical/query-engine/sql-expressions"
---

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

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

- [drizzle-orm/src/gel-core/dialect.ts](https://github.com/blade47/drizzle-orm/blob/main/drizzle-orm/src/gel-core/dialect.ts)
- [drizzle-orm/src/pg-core/dialect.ts](https://github.com/blade47/drizzle-orm/blob/main/drizzle-orm/src/pg-core/dialect.ts)
- [drizzle-orm/src/sql/sql.ts](https://github.com/blade47/drizzle-orm/blob/main/drizzle-orm/src/sql/sql.ts)
- [drizzle-orm/src/singlestore-core/dialect.ts](https://github.com/blade47/drizzle-orm/blob/main/drizzle-orm/src/singlestore-core/dialect.ts)
- [drizzle-orm/src/sqlite-core/dialect.ts](https://github.com/blade47/drizzle-orm/blob/main/drizzle-orm/src/sqlite-core/dialect.ts)
- [drizzle-orm/src/sql/expressions/conditions.ts](https://github.com/blade47/drizzle-orm/blob/main/drizzle-orm/src/sql/expressions/conditions.ts)
</details>

SQL Expressions are the fundamental building blocks of Drizzle ORM's query-building system. They provide a unified, type-safe abstraction for constructing SQL queries across different database dialects while maintaining portability and expressive power. By encapsulating raw query parts into composable objects, the library allows developers to write SQL using familiar TypeScript syntax that safely handles parameter binding and escaping without sacrificing direct control over the generated query structure.

The system is designed around the `SQL` class, which serves as the core container for query fragments (chunks). These chunks can be strings, column references, table references, nested SQL expressions, or user-provided parameters. This architecture treats a query as an abstract syntax tree of fragments, which is only flattened into a final string and a set of parameters at the very last moment by a dialect-specific engine. This deferred execution ensures that the driver handles parameter binding consistently and securely.

Beyond simple composition, the SQL Expression system acts as the bridge between TypeScript's type system and the database's execution layer. It manages driver-specific value encoding and decoding, identifier escaping, and placeholder transformation. Because the system is built recursively—where expressions can contain sub-expressions—it enables the creation of complex, modular queries that are easy to maintain, test, and adapt to different database backends (Gel, PostgreSQL, SQLite, SingleStore).

## The Core `SQL` Container

The `SQL` class is the central orchestrator for query fragment management. It accepts an array of `SQLChunk` objects and maintains a list of `usedTables` for internal tracking. The primary responsibility of this class is to serve as a builder that can aggregate query fragments via the `append` method, allowing for dynamic query construction.

Crucially, `SQL` instances are immutable in their definition, but the builder functions like `sql.join` or the `sql` template literal create new instances, ensuring that queries are composed safely. The `SQL` class exposes the `getSQL()` method, which fulfills the `SQLWrapper` interface, ensuring that any expression (a table, a column, or a subquery) can be treated uniformly by the query builder.

Sources: [drizzle-orm/src/sql/sql.ts:103-130](https://github.com/blade47/drizzle-orm/blob/main/drizzle-orm/src/sql/sql.ts#L103-L130)

## Template Literals and Composition

The `sql` tagged template literal is the primary entry point for developers to write SQL queries. When invoked, it tokenizes the input template and wraps variables in appropriate `SQLChunk` types. This transformation is not merely syntactic sugar; it ensures that every interpolated value is treated as part of the query structure, which helps the system distinguish between query keywords (strings) and dynamic content (parameters, identifiers, or other expressions).

The mechanism works by alternating between `StringChunk` instances (for raw text) and the interpolated expressions passed as arguments. This sequence is then fed into a new `SQL` instance.

```typescript
// Example of how the SQL expression system builds fragments
const query = sql`SELECT * FROM ${users} WHERE ${eq(users.id, 1)}`;
```
*In this example, the system tracks the `users` table reference separately from the condition `eq(...)`, allowing the dialect to later perform dialect-specific identifier escaping for both.*

Sources: [drizzle-orm/src/sql/sql.ts:485-495](https://github.com/blade47/drizzle-orm/blob/main/drizzle-orm/src/sql/sql.ts#L485-L495)

## Dialect-Specific Compilation

The compilation process, or `sqlToQuery`, is where the abstract `SQL` container is flattened into a runnable format for a specific database driver. The `SQL.toQuery` method is responsible for iterating over `queryChunks` and executing transformations based on a `BuildQueryConfig`.

The dialect provides specific implementation logic for `escapeName`, `escapeParam`, and `escapeString`. This ensures that, for instance, a MySQL/SingleStore backend uses backticks while a PostgreSQL/Gel backend uses double quotes for identifiers.

```mermaid
flowchart TD
    A["sql.toQuery(config)"] --> B["mergeQueries(chunks.map)"]
    B --> C{Chunk Type?}
    C -->|StringChunk| D["Return raw string"]
    C -->|Column| E["Escape identifier & concat table"]
    C -->|Param| F["Map to driver value & call escapeParam"]
    C -->|SQL| G["Recursive call: buildQueryFromSourceParams"]
    F --> H["Return query object {sql, params}"]
```

Sources: [drizzle-orm/src/sql/sql.ts:137-146](https://github.com/blade47/drizzle-orm/blob/main/drizzle-orm/src/sql/sql.ts#L137-L146), [drizzle-orm/src/pg-core/dialect.ts:609-618](https://github.com/blade47/drizzle-orm/blob/main/drizzle-orm/src/pg-core/dialect.ts#L609-L618)

## Parameter Binding and Encoding

Parameter binding is managed by the `Param` class and the `DriverValueEncoder` interface. When a parameter is encountered during query compilation, the system invokes `encoder.mapToDriverValue()`. This is a critical architectural step: it allows the ORM to convert complex TypeScript types (like `Date`, `JSON` objects, or custom classes) into formats the underlying database driver understands.

> [!NOTE]
> If a value is wrapped in `Param`, the system checks if it is a `Placeholder`. If it is, the system defers binding until the final query execution time, which allows for prepared statements.

Sources: [drizzle-orm/src/sql/sql.ts:432-450](https://github.com/blade47/drizzle-orm/blob/main/drizzle-orm/src/sql/sql.ts#L432-L450)

## Condition Expressions

Conditions (like `eq`, `lt`, `gt`) are implemented as wrappers around the `sql` template literal. These functions take arguments, apply `bindIfParam` to ensure they are properly encoded, and return a `SQL` object that can be further composed in a `where()` clause.

The `bindIfParam` function acts as a guard that prevents double-wrapping of parameters if they are already identified as an `SQLWrapper` or a `Column`.

```typescript
// The implementation of eq is a straightforward wrapper
export const eq: BinaryOperator = (left: SQLWrapper, right: unknown): SQL => {
    return sql`${left} = ${bindIfParam(right, left)}`;
};
```

Sources: [drizzle-orm/src/sql/expressions/conditions.ts:17-64](https://github.com/blade47/drizzle-orm/blob/main/drizzle-orm/src/sql/expressions/conditions.ts#L17-L64)

## Structural Design Trade-offs

The SQL Expression architecture prioritizes flexibility and cross-dialect portability over absolute runtime performance. The decision to use a recursive `SQL` structure introduces minor overhead due to tree traversal during query serialization, but it buys significant architectural benefits.

| Design Choice | Benefit | Cost |
| :--- | :--- | :--- |
| **Recursive Tree Structure** | Enables complex, nested query fragments. | Traversing nodes during compilation adds runtime overhead. |
| **Deferred Compilation** | Allows dialect-specific optimizations at the last minute. | Query compilation is strictly synchronous or asynchronous at the point of execution. |
| **Type-safe Encoding** | Prevents incorrect parameter types from reaching the database driver. | Requires maintaining `DriverValueEncoder` for every supported type. |

Sources: [drizzle-orm/src/sql/sql.ts:103-372](https://github.com/blade47/drizzle-orm/blob/main/drizzle-orm/src/sql/sql.ts#L103-L372)

## Related

- [Query Builder Core](https://www.doc0.app/docs/e1b68fed-3c4e-4c95-b2ba-ebf050f78025/technical/query-engine/query-builder-core)


## Sitemap

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