Compose reusable subqueries
Prepare an aggregate or filtered subquery once and reference it from a larger SQL statement.
Drizzle ORM · Module
db.with(...) attaches a named common table expression to a subsequent query. Define the expression with db.$with(...).as(...), then use it with insert, update, delete, or select operations.
db.with(...) attaches one or more named common table expressions to a subsequent insert, update, delete, or select query. The expression is created with db.$with(name).as(...), then referenced in the query through its alias.
db.with(cte).select(...)
db.with(cte).insert(...)
db.with(cte).update(...)
db.with(cte).delete(...)The page shows the result assigned from the executed query; the returned shape is determined by the query's returning projection.
$with(name).as(...).returning.import { drizzle } from 'drizzle-orm/node-postgres';
import { sql } from 'drizzle-orm';
import { orders } from './schema';
const averageAmount = db.$with('average_amount').as(
db.select({ value: sql`avg(${orders.amount})`.as('value') }).from(orders),
);
const result = await db
.with(averageAmount)
.delete(orders)
.where(sql`${orders.amount} > (select * from ${averageAmount})`)
.returning({ id: orders.id });This composes a named common table expression with a delete statement and returns deleted identifiers.
Prepare an aggregate or filtered subquery once and reference it from a larger SQL statement.
Apply a CTE while modifying rows with an insert, update, or delete operation.
db.$with('name').as(...) defines a named common table expression, and .with(cte) makes it available to the following query. The CTE can then be referenced through its alias inside expressions or query sources.
Follow-up: How would you reuse the same CTE in a write query? Define it once, pass it to .with(...), and reference its alias in the insert, update, or delete statement.
db.with be used with DELETE?The documented pattern is to build an aggregate subquery with $with, then call .with(...) before .delete(...). The resulting query can use the named CTE in a predicate and return selected fields.
Follow-up: What kind of SQL construct does this represent? It is a common table expression, allowing a named subquery to be composed with the main statement.
$with alias play?The CTE is named with $with('average_amount'), while .as(...) supplies its query body. The name is also the handle used when embedding the CTE in SQL expressions such as a scalar subquery.
Follow-up: Why alias the aggregate column? Give the selected expression an explicit name so the CTE exposes a stable, usable column name.
$withsqldeletereturningWITH statements