Query Builder
Build type-safe SQL with a fluent API backed by Bun’s tagged template literals. All table/column types are inferred from your model files.
Basics
ts
const rows = await db
.selectFrom('users')
.where({ active: true })
.orderBy('created_at', 'desc')
.limit(10)
.execute()where({})for equality; tuple[col, op, val]for explicit operatorsorderBy,orderByDesc,latest,oldest,inRandomOrdergroupBy,havingunion,unionAll
Joins
ts
await db
.selectFrom('users')
.leftJoin('projects', 'users.id', '=', 'projects.user_id')
.where(['projects.status', '=', 'active'])
.execute()Also join, innerJoin, rightJoin, crossJoin, joinSub, leftJoinSub, crossJoinSub.
Raw helpers
whereRaw,groupByRaw,havingRaw,selectRawwhereColumnandorWhereColumnwhereNestedandorWhereNested
Best Practices
- Prefer composable helpers over raw strings where possible
- Use
selectAllRelations()withwith()to alias related columns safely - For large result sets, prefer
paginate/simplePaginate/cursorPaginate
API Surface
- Selection
selectFrom(table)→ start a SELECT*select(table, ...columns)→ select specific columns; supports"expr as alias"
- Filtering
where(object)equality map;where([col, op, value]);andWhere,orWherewhereNull,whereNotNull,whereBetween,whereNotBetween,whereDate,whereRawwhereColumn,orWhereColumn,whereNested,orWhereNested
- Ordering & limits
orderBy,orderByDesc,latest(column?),oldest(column?),inRandomOrder(),reorder()limit,offset,forPage(page, perPage)
- Joins
join,innerJoin,leftJoin,rightJoin,crossJoin- Subquery joins:
joinSub,leftJoinSub,crossJoinSub
- Grouping & unions
groupBy,groupByRaw,having,havingRawunion,unionAll
- Modifiers
distinct,distinctOn(...columns)(Postgres)
- Execution
toSQL()→ Bun query object;execute(),values(),raw(),cancel()simple()→ run using Postgres “simple” protocol (multi-statement, no parameters)- Optional
(q as any).toText?.()ifconfig.debug.captureText = true
Insert / Update / Delete
insertInto(table).values(object|object[])updateTable(table).set(object).where(...)deleteFrom(table).where(...)- All support
returning(...columns)on PG
Examples
ts
// select subset
await db.select('users', 'id', 'email').where({ active: true }).execute()
// nested conditions
await db
.selectFrom('users')
.whereNested(
db.selectFrom('users').where(['age', '>=', 18]),
)
.execute()