Skip to content

Current limitations

  • Support applies to specific combinations of database, driver and runtime. The runtime and driver support matrix is the authoritative source. It records the exact tuple of database, driver, profile, runtime and capability, and its tested versions.
  • db.all() is materialized. It returns a readonly array. It uses application memory in proportion to the row count. When bounded application memory is important, use db.stream().
  • Routine streaming is not included. callStream() is reserved and not implemented. It is not a 1.0.0 API that you can call. The materialized db.call() reads and closes routine resources before mapping. Raw cursors, portals, requests and carrier rows never escape.
  • MySQL and MariaDB prepared CALL OUT/INOUT descriptors are unsupported. Emitted heterogeneous CALL result sets are supported. Neither mysql2 3.x nor MariaDB Connector/Node.js exposes a proven public discriminator for prepared call OUT carriers. Thus, SQLBraid does not guess a carrier row.
  • PostgreSQL refcursor calls require an existing transaction. A refcursor is a portal that belongs to a transaction. It is not an independent ResultSet. SQLBraid does not create a hidden transaction.
  • SQL Server cursor output is not an application cursor. CURSOR VARYING OUTPUT is not exposed as a client ResultSet that you can bind. Emitted SELECT rows stay ordinary result sets.
  • SQLite db.call() / routine.call is unsupported. This is a boundary of the adapter API. It is not a restriction on SQLite SQL. Scalar, aggregate and window functions and virtual-table extensions stay ordinary SQL. D1 also has no callback transaction and no incremental cursor.
  • DML-returning is materialized. Use sql.rows with db.execute, db.all, db.one or db.maybeOne. Do not infer that RETURNING/OUTPUT can stream on all drivers.
  • db.bulk() is for commands only. It locks one DML shape, validates all inputs before I/O, uses one lease and reports the actual mode. Root bulk has no portable promise of atomicity or automatic chunking. For atomicity, use db.tx().
  • Sessions and transactions are APIs for the physical scope. db.session() pins one provider lease. Nested session and transaction work uses the same lease. Root escape and closed or sibling handles are rejected. Missing primitives use BRAID_SESSION_UNSUPPORTED or BRAID_TX_UNSUPPORTED.
  • Transaction options are fixed and depend on capabilities. Isolation is one of read-uncommitted, read-committed, repeatable-read or serializable. readOnly is separate. Malformed runtime values fail before acquisition with TypeError / BRAID_TX_OPTIONS_INVALID. Valid but unsupported values use BRAID_TX_OPTION_UNSUPPORTED. Nested explicit options use BRAID_TX_OPTIONS_NESTED.
  • Explicit access modes are unsupported for Bun.SQL MySQL/MariaDB. Both readOnly: true and readOnly: false reject before I/O with BRAID_TX_OPTION_UNSUPPORTED / transaction.read-only. In native Bun 1.3.14, read-only statement failures can survive a rollback. Contaminated reservations are discarded. If you omit the option, the session default stays. Read-write is not forced. Bun.SQL PostgreSQL and the representation-profile options do not change.
  • Cancellation depends on capabilities. An already-aborted signal keeps its reason. An active signal without physical cancellation fails before I/O with UnsupportedFeatureError / BRAID_CANCEL_UNSUPPORTED. To stop the iteration alone is not cancellation.
  • No universal input codec. The driver binds ordinary interpolation. Application conventions for JSON, temporal values, custom classes and binary values stay the concern of the driver and the application.
  • Numeric fidelity is specific to the profile. Exact database integers and decimals are canonical strings. Approximate IEEE values are numbers. decodeExactInteger is an optional application transform. Bun 1.3.14 uses { bigint: true } for PostgreSQL, MySQL and MariaDB, and { safeIntegers: true } for SQLite. Integral Number rows reject. PostgreSQL decimal is text. MySQL and MariaDB DECIMAL and binary byte carriers reject, unless your SQL converts them to text or hex. SQLite native decimal is unsupported. D1 stays guarded to its safe-integer range. When exact text is important, write CAST(... AS TEXT) in your SQL.
  • JSON and temporal fidelity are separate profiles. Parsed JSON can contain rounded nested numbers. Native Date can lose fractional precision or offset and zone semantics. Use a tested text profile, or write JSON_SERIALIZE, TO_CHAR or CONVERT in your SQL.
  • Containers are not scalar guarantees. Arrays, domains, ranges, multiranges, composites, Oracle objects and collections, SQL Server sql_variant, vectors and nested values stay unclassified or unsupported until they are tested.
  • The profile and codegen must agree. If you change the JSON, temporal or numeric options of a driver, you create a different evidence profile. The runtime and the generated models must use its TypePolicy.
  • The user selects the Bun SQL dialect. createBunSqlDatabase requires dialect: "postgres" | "mysql" | "mariadb" | "sqlite". The adapter does not detect it automatically. In Bun 1.3.14, active cancellation fails with BRAID_CANCEL_UNSUPPORTED. Stream and routine carriers fail explicitly with BRAID_STREAM_UNSUPPORTED and BRAID_CALL_UNSUPPORTED. The result.rows and result.command metadata is guarded by bun-sql.result-kind-metadata. For MySQL and MariaDB, an empty SELECT and DML or DDL that affects zero rows fail after execution with BRAID_RESULT_KIND_AMBIGUOUS. Thus, side effects can already have occurred.
  • Deno uses the existing adapters. A public Node-compatible driver path can work in Deno. This does not create a Deno dialect or promote a support tuple.
  • No SQL-to-TypeScript inference. SQLBraid does not infer the results of arbitrary SELECT and JOIN statements or hydrate relation graphs.
  • Observers cannot change, retry or route. Observers can inspect or fail an operation. They cannot rewrite SQL, change binds, retry or route.
  • Metadata is evidence. It does not prove invalidity. Missing objects are open-world. Routine argument lists can be incomplete.
  • Custom drivers are not release support. Implement QueryExecutor/ConnectionProvider and supply independent exact evidence.
  • Tooling is Node-first. The compiler, CLI, LSP, metadata and codegen, and the Vite integration have separate build and runtime concerns. Do not put drivers that are only for Node into browser bundles.

These boundaries are intentional. They are not hidden fallback behavior. Read routine calls, streaming, transactions and the support matrix.