Skip to content

SQL Server quickstart

This page needs Node >=22.18.0 and Docker. Node 22.18.0 runs the TypeScript example directly.

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.

Terminal window
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.04
until 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; done
docker exec -i braid-mssql /opt/mssql-tools18/bin/sqlcmd -C -S localhost -U sa -P 'Password!123' <<'SQL'
CREATE DATABASE app;
GO
USE app;
CREATE TABLE users (id INT IDENTITY PRIMARY KEY, name NVARCHAR(200) NOT NULL);
INSERT INTO users (name) VALUES (N'Ada'), (N'Grace');
GO
SQL
export SQLSERVER_TRUST_SERVER_CERTIFICATE=true

The container uses a self-signed certificate. The last command trusts it for this local server only.

Install the SQLBraid runtime facade, the SQL Server dialect package and Tedious together:

Terminal window
mkdir braid-mssql-app && cd braid-mssql-app
pnpm init --init-type module
pnpm add sqlbraid @sqlbraid/mssql tedious@20.0.0
mkdir src

@sqlbraid/mssql declares the exact peer version Tedious 20.0.0. A later Tedious version causes a peer dependency warning.

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.

  • 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 OUTPUT is not an application cursor channel. It is rejected with BRAID_CALL_CURSOR_UNSUPPORTED. Batches that read a local cursor and emit SELECT rows 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 example CAST(@nvarchar_parameter AS decimal(38, 18)). The native typed DECIMAL/NUMERIC/MONEY convenience path is bounded JavaScript number input. It does not give arbitrary-precision fidelity.
  • Native temporal values use Date. Date does not keep the 100ns precision or the complete offset semantics of SQL Server. When exact temporal text is important, write CONVERT(varchar(...), datetime2_or_datetimeoffset, style).

For the shape of the explicit procedure metadata and the heterogeneous sql.call result rules, read routine calls.

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 and TYPES.* metadata.
  • Native OUTPUT rows are materialized through sql.rows. The output and return routine channels use explicit metadata.
  • Prepared-loop is the portable bulk strategy.
  • affectedRows and the procedure status stay operational counts with safe-range checks. IDs that the database generates use exact text where the driver exposes it.
  • Ordinary undefined IN values fail before acquisition with BRAID_BIND_VALUE_UNSUPPORTED. null is SQL NULL.
  • Native SQL passes through without change. SQLBraid does not claim to parse all T-SQL grammar.