SQL Server quickstart
This page needs Node >=22.18.0 and Docker. Node 22.18.0 runs the TypeScript example directly.
1. Start a database
Section titled “1. Start a database”Start a local SQL Server and create the database and the table that the example reads. If you have a server with a users table, set the SQLSERVER_* variables of the example and skip this step.
docker run -d --name braid-mssql -e ACCEPT_EULA=Y -e MSSQL_SA_PASSWORD='Password!123' -p 1433:1433 mcr.microsoft.com/mssql/server:2022-CU18-ubuntu-22.04until docker exec braid-mssql /opt/mssql-tools18/bin/sqlcmd -C -S localhost -U sa -P 'Password!123' -Q "SELECT 1" >/dev/null 2>&1; do sleep 2; donedocker exec -i braid-mssql /opt/mssql-tools18/bin/sqlcmd -C -S localhost -U sa -P 'Password!123' <<'SQL'CREATE DATABASE app;GOUSE app;CREATE TABLE users (id INT IDENTITY PRIMARY KEY, name NVARCHAR(200) NOT NULL);INSERT INTO users (name) VALUES (N'Ada'), (N'Grace');GOSQLexport SQLSERVER_TRUST_SERVER_CERTIFICATE=trueThe container uses a self-signed certificate. The last command trusts it for this local server only.
2. Create a project
Section titled “2. Create a project”Install the SQLBraid runtime facade, the SQL Server dialect package and Tedious together:
mkdir braid-mssql-app && cd braid-mssql-apppnpm init --init-type modulepnpm add sqlbraid @sqlbraid/mssql tedious@20.0.0mkdir src@sqlbraid/mssql declares the exact peer version Tedious 20.0.0. A later Tedious version causes a peer dependency warning.
3. Run a query
Section titled “3. Run a query”The portable root exposes the SQL Server dialect and the hint factories. The Node driver adapter is under /tedious. Save this code as src/index.ts and run node src/index.ts:
import { Connection } from "tedious";import { createTediousDatabase } from "@sqlbraid/mssql/tedious";import { mssqlParameter, sql } from "@sqlbraid/mssql";
interface UserRow { id: string; name: string;}
const connection = new Connection({ server: process.env.SQLSERVER_HOST ?? "localhost", authentication: { type: "default", options: { userName: process.env.SQLSERVER_USER ?? "sa", password: process.env.SQLSERVER_PASSWORD ?? "Password!123", }, }, options: { database: process.env.SQLSERVER_DATABASE ?? "app", encrypt: true, trustServerCertificate: process.env.SQLSERVER_TRUST_SERVER_CERTIFICATE === "true", },});await new Promise<void>((resolve, reject) => { connection.once("connect", (error) => (error ? reject(error) : resolve())); connection.connect();});const db = createTediousDatabase(connection);
try { const name = "Ada"; const users = await db.all(sql.rows<UserRow>` SELECT id, name FROM users WHERE name = ${sql.bind(name, mssqlParameter.nvarchar(200))} `); console.log(users);} finally { connection.close();}When you finish, stop the server with docker rm -f braid-mssql.
TLS encryption and certificate verification are enabled by default. Set
SQLSERVER_TRUST_SERVER_CERTIFICATE=true explicitly only for an isolated local
development server with a self-signed certificate. Do not use that bypass for
remote or production servers. Configure a trusted certificate.
Tedious receives deterministic parameter names: @p1, @p2, …. sql.bind selects the database type. It does not turn the value into SQL text. Scalar OUTPUT and INOUT routine parameters require explicit hints. To get a T-SQL integer RETURN status, give explicit procedure: { name, parameterNames } metadata in the sql.call declaration. SQLBraid does not parse arbitrary EXEC text to guess the identity.
The Tedious binding adapter materializes a logical statement as a typed request:
deterministic @p1, @p2, … names, TYPES.* mappings, encoded values and
facets. The description, the hint validation and the exactness checks occur
before lease acquisition. Tedious owns the effective reuse. Failures in this
work are materialize errors without driver I/O.
Capability boundaries
Section titled “Capability boundaries”- The tested target is Tedious 20.0.0 against SQL Server 2022 CU18 Developer on Node 22.18.0 (Linux x64). See the runtime and driver support matrix for per-capability status.
- Common values without a hint use the Tedious inference of the adapter. Use an explicit hint for
null, custom objects, precision and scale, lengths or SQL Server-specific types. - The adapter keeps multiple recordsets. It does not flatten them into invented single-row results.
CURSOR VARYING OUTPUTis not an application cursor channel. It is rejected withBRAID_CALL_CURSOR_UNSUPPORTED. Batches that read a local cursor and emitSELECTrows return those rows as ordinary result sets.
Tedious exposes decimal/numeric, money and smallmoney through a
JavaScript number. Thus, SQLBraid fails closed with BRAID_RESULT_EXACTNESS.
It does not convert a lossy exact value to a string. Tedious BIGINT text is
normalized to the canonical exact string.
- For exact decimal or money results, write a text expression such as
CONVERT(varchar(100), exact_column)with a correct length. Declare a string result. - For exact input, use a character hint (
mssqlParameter.nvarchar(...)). Let your SQL select the conversion, for exampleCAST(@nvarchar_parameter AS decimal(38, 18)). The native typed DECIMAL/NUMERIC/MONEY convenience path is bounded JavaScriptnumberinput. It does not give arbitrary-precision fidelity. - Native temporal values use
Date.Datedoes not keep the 100ns precision or the complete offset semantics of SQL Server. When exact temporal text is important, writeCONVERT(varchar(...), datetime2_or_datetimeoffset, style).
For the shape of the explicit procedure metadata and the heterogeneous
sql.call result rules, read routine calls.
Tedious representation profile
Section titled “Tedious representation profile”This profile applies to SQL Server 2022 CU18 Developer with Tedious 20.0.0 on Node 22.18.0/Linux x64.
| SQL Server value | Driver raw / SQLBraid canonical representation | Status/caveat |
|---|---|---|
tinyint / smallint / int / bigint |
string | Exact integer transport is canonical text; decodeExactInteger is an application opt-in. |
decimal / numeric / money / smallmoney |
number → unsupported for exact output | Use a character bind plus authored text CAST/CONVERT; do not stringify a lossy Number. |
real / float |
JavaScript number |
Approximate binary32/binary64 values; SQL Server does not claim NaN/Infinity support. |
datetime2 / datetimeoffset |
Date |
Native convenience profile; use authored ISO/text conversion for 100ns or offset fidelity. |
uniqueidentifier |
string | Validate with the application schema if required. |
varbinary |
Buffer |
Keep bytes or explicitly encode. |
| JSON | text | SQL Server JSON is character data; SQLBraid does not parse it, so text can preserve nested numeric lexemes. |
- The binding transport is a typed Tedious request with deterministic
@p1,@p2, … names andTYPES.*metadata. - Native
OUTPUTrows are materialized throughsql.rows. The output and return routine channels use explicit metadata. - Prepared-loop is the portable bulk strategy.
affectedRowsand the procedure status stay operational counts with safe-range checks. IDs that the database generates use exact text where the driver exposes it.- Ordinary
undefinedIN values fail before acquisition withBRAID_BIND_VALUE_UNSUPPORTED.nullis SQLNULL. - Native SQL passes through without change. SQLBraid does not claim to parse all T-SQL grammar.