Skip to content
masterclassBuddyTech Buzz5 fresh blogs · 5:00 AM IST

Drizzle ORM · Function

sql

Drizzle's sql template builds composable, type-safe SQL fragments for use inside query-builder clauses or direct execution. Schema objects are escaped and runtime interpolations are emitted as bound parameters.

How it works

The sql template creates composable SQL fragments that can be embedded in Drizzle queries or executed directly. Tables and columns are converted into escaped SQL identifiers, while interpolated runtime values become bound parameters; sql<T> only guides TypeScript and does not transform results at runtime.

Syntax

sql`...${value}...`

Parameters

NameTypeDescription
template literalTemplateStringsArray and interpolated valuesSQL template chunks and interpolated Drizzle SQL wrappers, tables, columns, or runtime values.

Returns

A composable SQL fragment; when executed, it produces SQL text plus separately bound parameters.

Key points

  • Use the template when the query builder does not express a particular SQL construct conveniently.
  • SQL fragments can be inserted into only the needed part of a larger builder query.
  • The template is supported in projections and major query clauses, including filtering, sorting, grouping, and aggregation.
  • Interpolated schema objects receive dialect-aware identifier escaping.
  • Interpolated runtime values are parameterized rather than concatenated into SQL text.
  • Import the template from the main drizzle-orm package.

Common mistakes

  • The generic type annotation affects compile-time typing only; it does not convert database results at runtime.
  • Use raw SQL only when you intentionally accept responsibility for escaping and injection safety.
  • When extracting generated SQL and parameters, provide the target dialect so Drizzle can format them correctly.

Example: Parameterized SQL fragment

import { sql } from 'drizzle-orm';

const id = 69;
const query = sql`select * from ${usersTable} where ${usersTable.id} = ${id}`;
await db.execute(query);

Builds a parameterized query that filters the users table by an ID while letting Drizzle escape identifiers and bind the value.

When to use it

Express custom SQL

A query needs a database expression that is not directly represented by the builder.

Extend builder queries selectively

Only one clause requires SQL while the rest benefits from Drizzle's builder API.

Add computed selections

A computed field needs a SQL function or expression.

Execute custom statements

A query must execute a complete parameterized SQL statement.

Interview questions

QWhat is the purpose of Drizzle's sql template?

The sql template lets you write SQL fragments that remain composable with Drizzle's query builder. It supports partial statements such as SELECT expressions, filters, ordering, grouping, and relational-query extras.

Follow-up: How are interpolated values handled? Runtime values are converted to placeholders and sent separately as parameters, while tables and columns are escaped as identifiers.

QHow does interpolation affect generated SQL?

Interpolated tables and columns are mapped to escaped SQL syntax, including qualified column names. Dynamic values such as an ID become placeholders such as $1, with their actual values stored separately.

Follow-up: What does sql<T> add? It supplies a TypeScript-only result type and performs no runtime mapping.

QWhen would sql.raw() be appropriate?

Use sql.raw() when deliberately inserting SQL text without Drizzle's normal processing or escaping. This is different from normal interpolation, which preserves identifier escaping and parameter binding.

Follow-up: How can generated SQL be inspected? Specify the database dialect when obtaining the query string and its parameters.

  • sql.raw()
  • sql<T>
  • db.execute()
  • SQLWrapper
  • Drizzle query builder

Source: Magic sql`` operator - Drizzle ORM. Checked 2026-10-16.