tedious
A pure-JavaScript TDS driver that lets Node.js applications talk directly to Microsoft SQL Server.
Repository Health
Technical Analysis
Tedious is a pure-JavaScript implementation of Microsoft’s Tabular Data Stream (TDS) protocol, giving Node.js applications a direct wire-level client for SQL Server without any native bindings. It handles the full connection lifecycle — TCP/TLS negotiation, SQL Server instance discovery via SQL Browser, NTLM and Azure Active Directory (including Managed Identity and Default Azure Credential) authentication, and TDS version negotiation back to SQL Server 2000.
Beyond basic query execution, Tedious exposes SQL Server-specific capabilities that generic SQL clients don’t: bulk insert via BulkLoad, table-valued parameters, stored procedure calls with typed parameters across more than 30 native TDS column types, and Always Encrypted column-level encryption backed by Azure Key Vault. Its API is deliberately low-level and event-driven — Connection and Request objects emit events for rows, column metadata, and completion — which keeps it close to the protocol and makes it a common foundation underneath higher-level libraries such as mssql and Sequelize’s SQL Server dialect, rather than a query-builder in its own right.
The project has been maintained since 2011 and is actively developed, with CI running its unit and integration suites against real SQL Server instances in Docker across multiple Node.js and TDS versions.
What You Get
- A
Connectionclass handling TCP/TLS setup, SQL Browser instance lookup, and TDS version negotiation down to SQL Server 2000 - NTLM and Azure AD authentication, including Managed Identity, Default Azure Credential, and client-secret service principal flows
BulkLoadfor high-throughput bulk inserts and native support for table-valued parameters and stored procedure calls- Always Encrypted column encryption with Azure Key Vault-backed key unwrapping for querying encrypted columns without exposing plaintext to the server
- Native support for 30+ TDS data types (decimal, numeric, datetime2, datetimeoffset, xml, udt, sql_variant, and more) with precise wire-format encoding/decoding
- Event-driven
Requestobjects streamingcolumnMetadata,row, anddoneevents for full control over result processing
Common Use Cases
- Connecting a Node.js backend directly to an on-prem or Azure SQL Server database without native/ODBC drivers
- Serving as the underlying driver for a higher-level ORM or query builder that targets SQL Server (as
mssqland Sequelize’s SQL Server dialect do) - Bulk-loading large datasets into SQL Server tables via
BulkLoadinstead of row-by-row inserts - Authenticating to Azure SQL Database using Managed Identity or Azure AD credentials instead of SQL logins
- Querying and writing Always Encrypted columns from a Node.js service while keeping sensitive data encrypted at rest and in transit
Under The Hood
Architecture
Tedious is organized around a Connection class that drives a protocol state machine — prelogin, then NTLM or Azure AD login (login7-payload.ts, ntlm-payload.ts), followed by token-stream parsing and request execution — implemented across a clear separation between transport (connector.ts, message-io.ts, packet.ts), protocol encoding (login7-payload.ts, prelogin-payload.ts, rpcrequest-payload.ts, sqlbatch-payload.ts, bulk-load-payload.ts), data marshaling (data-type.ts plus 30+ files under data-types/), and column-encryption support (always-encrypted/). Incoming TDS token streams are parsed by a dedicated token-stream-parser dispatching to per-phase handler classes (Login7TokenHandler, RequestTokenHandler, AttentionTokenHandler). This layering is clean, but the handler classes and payload builders are tightly coupled to the Connection lifecycle, so changes to the core state machine would ripple across most of the protocol-encoding layer.
Tech Stack
Written in TypeScript but compiled via Babel (@babel/preset-typescript and @babel/preset-env targeting Node 22) rather than tsc, with tsc used separately only to emit type declarations (tsconfig.build-types.json). Runtime dependencies are narrow and purpose-built: @azure/identity, @azure/core-auth, and @azure/keyvault-keys for Azure AD and Always Encrypted key-unwrapping, @js-joda/core for temporal value handling, bl for buffer-list stream assembly, and iconv-lite for character-encoding conversions. The published package ships both compiled JS (lib/) and generated .d.ts type declarations.
Code Quality
The test suite is extensive: a unit suite under test/unit covering nearly every module (connection handling, bulk load, each token/payload type) using Mocha, Chai, and Sinon with nyc coverage, plus a separate integration suite that runs against a real SQL Server instance in Docker (test/docker-compose.linux.yml) across multiple TDS and Node.js versions in CI. Errors use typed subclasses (ConnectionError, RequestError, InputError) carrying protocol-specific fields like number, state, and serverName rather than generic Error objects. Linting combines ESLint’s flat config with a tsc type-check gate, and CodeQL static analysis runs in CI alongside PR-title linting.
API Design
The public API is intentionally low-level and event-driven rather than promise-based — Connection and Request objects emit columnMetadata, row, done, and error events, mirroring the underlying protocol closely instead of hiding it behind a query builder. This gives direct access to SQL Server-specific behavior (bulk loads, table-valued parameters, Always Encrypted) that a generic SQL client wouldn’t expose, at the cost of more boilerplate for callers than a modern promise/async-iterator client would require — which is consistent with its role as the foundation underneath higher-level libraries rather than an end-user-facing client itself.
Used by 2 apps in this directory
Infisical
Security · Devops
The open-source platform for secrets, certificates, privileged access, and AI agent security — all in one self-hostable system.
ToolJet
Low Code Platforms · No Code Platforms · AI Agents
Open-source AI-native platform to build and deploy internal tools, workflows, and AI agents with a visual drag-and-drop builder and 80+ data source integrations.