Skip to main content
The SQL DSL (db.sql) is Prisma Next’s lower-level query builder. It lets you compose type-safe SQL plans from individual operations — select, where, order, limit, join — without writing raw SQL strings. Plans are built offline (no network I/O) and executed separately, which makes them easy to inspect, test, and log.

Importing and using db.sql

db.sql is available on both the postgres() (Node) and postgresServerless() facades. It is part of the static authoring surface and is safe to use at module scope:

Selecting columns

Use .select() with field names from your contract. The return type is inferred from the columns you pick:

Filtering with .where()

The .where() callback receives two arguments: f (field references) and fns (built-in predicate functions). Use fns to build expressions:
Available fns predicates: eq, ne, gt, gte, lt, lte, in, notIn, and, or, exists, notExists. Extension packs may add additional predicates (for example, fns.cosineDistance from pgvector).

Ordering with .orderBy()

Pass a callback that selects a field and specifies a direction:

Limiting and paginating

Use .limit() for a hard row cap:
Use .innerJoin() or .outerLeftJoin() to bring in columns from a related table. Use .as() to alias tables, then reference fields by alias in the expression callback:
Available join types: innerJoin, outerLeftJoin, outerRightJoin, outerFullJoin, and lateralJoin (requires the lateral capability in your contract).

Mutations: insert, update, delete

The table proxy also exposes insert(), update(), and delete(). Mutation queries support .returning() to get back the affected rows:

Building a plan with .build()

.build() compiles the current builder state into a SqlQueryPlan. This is a pure in-memory operation — no database connection required:
Building and executing are separate steps. .build() produces a serializable plan object; runtime.execute(plan) sends it to the database. You can build plans at module scope, cache them, or serialize them for logging — none of that requires a live connection.

Executing a plan with runtime.execute()

Call db.runtime() (synchronous — returns the cached runtime) and pass the plan to execute():
For streaming large result sets, iterate directly:

Result types from contract.d.ts

The return type of runtime.execute(plan) is fully inferred from the columns you selected. No manual casting is needed:

Parameterized queries

Values you pass to fns predicates are automatically encoded as bind parameters — you never interpolate raw values into query strings: