Architecture mental model
SQLBraid is easiest to understand as a pipeline with deliberately narrow boundaries. The SQL text stays visible; values remain values; adapters own physical transport; runtime owns connection and scope correctness.
Execution path
The major boundaries from authored SQL to application values.
Package boundaries
The execution core and static tooling share contracts while keeping dependency direction separate.
@sqlbraid/corecontracts + invariants@sqlbraid/templateauthoring + rendering@sqlbraid/runtimephysical lifecycledriver adaptersDB/driver bridge@sqlbraid/compilersource discovery / lowering@sqlbraid/metadatadatabase evidence@sqlbraid/codegenmodel generation@sqlbraid/toolingworkspace / semantic toolingconsumersLSP / CLI / VS Code / ViteThe four execution layers
Section titled “The four execution layers”@sqlbraid/coredefines the contracts: logical statements, binding SPI, executor/provider SPI, runtime API, representation policy, observers, capabilities, routines, and public errors.@sqlbraid/templateturns tagged templates into frozenQueryvalues and renders explicit SQL structure into transport-neutralRenderedStatementobjects.@sqlbraid/runtimeowns leases, pinned scopes, transaction/savepoint continuity, streaming lifetime, cancellation boundaries, result-kind checks, and application mapping.- Driver adapters translate the logical statement/binding description into a native driver call and normalize native results back into SQLBraid contracts.
The invariant to remember
Section titled “The invariant to remember”segments.length===parameters.length + 1Ordinary ${value} interpolation is a bind value. It does not become SQL structure. Structural SQL requires an explicit helper such as sql.ident, sql.fragment, sql.list, sql.join, or the deliberate sql.raw escape hatch.
Placeholder syntax appears only at the binding/adapter boundary: PostgreSQL may use $1, MySQL ?, Oracle :1, SQL Server @p1, while native-template transports can keep a different physical representation.
Resource ownership is the runtime’s main job
Section titled “Resource ownership is the runtime’s main job”A pooled materialized query acquires a lease, performs physical I/O, releases the lease, and only then performs asynchronous Standard Schema mapping. A stream is different: its cursor/result set retains the resource until iterator cleanup finishes.
db.session() pins one resource without beginning a transaction. db.tx() begins one physical transaction on a pinned resource. Nested transactions are savepoints on that same resource, not independent transactions.
Using a root or parent handle in a way that could escape to another connection is rejected instead of silently rerouted. If transaction control or cleanup leaves a connection uncertain, SQLBraid poisons/discards the resource rather than optimistically reusing it.
Prepared, batch, and bulk are different contracts
Section titled “Prepared, batch, and bulk are different contracts”db.prepare()locks the logical SQLBraid shape; it does not promise a universal server-side prepared cache.db.batch()runs several possibly different operations on one physical use/lease but is not implicitly transactional.db.bulk()applies one homogeneous command shape to many inputs; the adapter chooses the physical bulk strategy.
TypePolicy is not application mapping
Section titled “TypePolicy is not application mapping”TypePolicy normalizes database/native driver values into SQLBraid’s canonical JavaScript representation. Standard Schema maps that canonical representation into application/domain values. Keeping these boundaries separate is what lets runtime stay free of a universal codec framework.
Tooling is a separate plane
Section titled “Tooling is a separate plane”The runtime packages do not depend on metadata, codegen, compiler, CLI, editor, or Vite packages. @sqlbraid/compiler owns source discovery/lowering; @sqlbraid/metadata records database evidence; @sqlbraid/codegen generates models from metadata plus TypePolicy; @sqlbraid/tooling combines positive evidence for LSP/CLI/editor features.
Missing metadata is unresolved evidence, not proof that user SQL is invalid.
Read the source in this order
Section titled “Read the source in this order”packages/core/src/index.ts:RenderedStatement,Query,StatementBindingAdapter,QueryExecutor,ConnectionProvider,Database,SqlTag.packages/template/src/index.ts:createSqlTag()and the rendering path.packages/runtime/src/index.ts:createScopedDatabase()→prepare()→leaseForUse()→physical()→runPrepared()→finalizePhysical()→processRows().- Runtime
stream(), thensession()andtx(). - PostgreSQL’s
pgStatementBinding/createPgExecutor()as a reference adapter, then Oracle for a resource-heavy adapter. - Compiler → metadata → codegen → tooling when working on static tooling.
For the full contributor-oriented walkthrough and invariants, see the repository’s English mental model. Driver implementers should also read the driver-author guide.