Overview
@sqb/builder is SQB's query builder: a standalone, driverless way to compose Select,
Insert, Update, and Delete statements as plain JS/TS objects, then serialize them to the
correct SQL text for whichever database you target. It has no driver and makes no network
connection — installing just @sqb/builder is enough to build and print SQL.
Why a query builder instead of raw strings
Concatenating SQL strings by hand gets error-prone fast — quoting identifiers correctly,
building a WHERE clause out of conditions that may or may not be present, keeping parameter
placeholders in sync with their values, and doing all of that differently for every database
you target. A hand-rolled string template also doesn't compose: adding one more optional filter
usually means restructuring the whole query.
@sqb/builder replaces that with a small set of chainable calls that read like the SQL they
produce:
import { Select, Eq } from '@sqb/builder';
const query = Select('id', 'given_name', 'family_name')
.from('customers')
.where(Eq('active', true))
.orderBy('id')
.limit(10);
Conditions, columns, and joins are values you can build up conditionally in plain JavaScript —
push another Eq()/In() into .where() only when a filter is actually present, no string
surgery required.
Why a query builder instead of a bespoke query DSL
Some ORMs invent their own filter syntax ({ where: { age: { gt: 18 } } }-style objects) that
you have to learn on top of SQL itself, and that inevitably can't express everything SQL can.
@sqb/builder's API stays close to SQL's own vocabulary — Select, .from(), .join(),
.where(), .groupBy(), .orderBy() — so what you already know about SQL mostly carries over
directly.
Why it matters that it's dialect-aware
The same query object can be serialized for different databases, and SQB accounts for the SQL differences between them. Take one simple query:
import { Select } from '@sqb/builder';
const query = Select('*').from('customers').limit(10);
With no dialect plugin imported at all, .generate() still works, but pagination isn't rendered —
.limit() is meaningless without dialect-specific knowledge of how to express it:
query.generate().sql;
// select * from customers
Import a dialect plugin and pass its name, and the exact same query object renders that
database's real pagination syntax:
import '@sqb/postgres-dialect';
query.generate({ dialect: 'postgres' }).sql;
// select * from customers LIMIT 10
import '@sqb/oracle-dialect';
// Oracle < 12c has no FETCH FIRST — the dialect plugin wraps the query in a rownum subquery instead
query.generate({ dialect: 'oracle', dialectVersion: '11' }).sql;
// select * from (select * from customers) where rownum <= 10
// Oracle 12c+ gained real FETCH FIRST syntax
query.generate({ dialect: 'oracle', dialectVersion: '12' }).sql;
// select * from customers FETCH FIRST 10 ROWS ONLY
import '@sqb/mssql-dialect';
query.generate({ dialect: 'mssql' }).sql;
// select * from customers ORDER BY (SELECT NULL) OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY
Nothing about query changed between these calls — only which dialect plugins were imported and
which dialect/dialectVersion were passed to .generate(). @sqb/builder never bundles dialect
logic itself, and .generate() doesn't validate the dialect name — forgetting the import doesn't
throw, it just silently falls back to the generic form shown first. See
The Dialect Plugin System for the full mechanism, and
Generating SQL per Dialect for the .generate() API itself.
Where to go next
- The sql Namespace — every symbol
@sqb/builderexports, in one place. - Select Statement, Insert Statement, Update Statement, and Delete Statement — one guide per statement type.
- Operators and Conditions —
Eq,In,Like,And/Or, and the rest. - Columns and Table References —
Field,TableName, and the column elements behindGROUP BY/ORDER BY/RETURNING. - Functions and Expressions —
Case,Coalesce,Count,Max/Min,Upper/Lower,StringAgg,Sequence. - The Dialect Plugin System — how
@sqb/postgres-dialect,@sqb/oracle-dialect, and the rest plug in, and how to write your own. - Pairing the builder with a client and a connection pool: Connecting & Pooling.