You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I guess you're talking about SQL Server Express LocalDB? If yes, this should be supported, as it's basically a slimmed down version of SQL Server. But no guarantees, as I never used that version before.
Did connecting to your LocalDB instance work before?
tedious currently does not know how to connect to a SQLServer instance through a named pipe. Nodejs supports named pipes on windows (only local named pipes), but correct handling for this was never implemented.
Another issue is that from my understanding, native TDS drivers from microsoft will start your localdb instance if it's not already running. tedious will never support this.
So overall, I stand corrected. As-is, tedious won't be able to connect to your LocalDB instance.
For anyone landing here, tedious can't resolve (localdb)\Instance itself, but it can connect to LocalDB if you hand it the instance's named pipe via the connector option (tedious ≥ 16.1.0). This works with mssql too, which is the easier route if that's what you use.
With mssql (Windows only, SqlLocalDB.exe must be on PATH; top-level await shown for brevity):
constsql=require("mssql");const{ execFile }=require("node:child_process");const{ promisify }=require("node:util");constnet=require("node:net");construn=promisify(execFile);// Starts the instance if needed and returns its named pipe, e.g. \\.\pipe\LOCALDB#5E134EF5\tsql\queryasyncfunctionlocalDbPipe(instance){awaitrun("SqlLocalDB.exe",["start",instance]);const{ stdout }=awaitrun("SqlLocalDB.exe",["info",instance]);constmatch=/Instancepipename:\s*np:(\S+)/i.exec(stdout);if(!match)thrownewError(`LocalDB instance ${instance} not found or has no pipe name`);returnmatch[1];}// Called by tedious for every new connection as (options, lookup, signal).constlocalDbConnector=(instance)=>(_options,_lookup,signal)=>newPromise((resolve,reject)=>{signal.throwIfAborted();signal.addEventListener("abort",()=>reject(signal.reason),{once: true});localDbPipe(instance).then((pipe)=>{if(!signal.aborted)resolve(net.connect({path: pipe}));},reject);});constpool=awaitnewsql.ConnectionPool({server: "(localdb)",// exactly this: not "(localdb)\\MSSQLLocalDB" (see below)user: "…",password: "…",database: "master",options: {encrypt: false,// LocalDB doesn't negotiate encryptionconnector: localDbConnector("MSSQLLocalDB"),},}).connect();
Things worth knowing:
Use server: "(localdb)", not "(localdb)\\MSSQLLocalDB", and don't use a Server=(localdb)\… connection string. mssql turns anything after the backslash into an instance name, which makes tedious look up a port through SQL Browser (LocalDB has none) before it ever calls the connector. Pass the instance name to the connector instead, as above.
You need a SQL login. tedious can't use Windows authentication. The LocalDB owner is a sysadmin, so you can create one with your Windows identity, for example (development only, since it makes the login a sysadmin): sqlcmd -S "(localdb)\MSSQLLocalDB" -E -Q "CREATE LOGIN dev WITH PASSWORD = '…', CHECK_POLICY = OFF; ALTER SERVER ROLE sysadmin ADD MEMBER dev"
Any tool that can connect with Windows authentication (SSMS, Azure Data Studio, PowerShell's Invoke-Sqlcmd) works equally well. If you need Windows authentication in your app, use mssql/msnodesqlv8 instead.
encrypt: false is required, otherwise the connection fails with "Server did not negotiate encryption".
Look the pipe up for every connection, as above. The instance stops itself about 5 minutes after its last connection closes and comes back on a different pipe, so a remembered pipe name breaks with ENOENT \\.\pipe\LOCALDB#… after your app has been idle.
Plain tedious (without mssql)
const{ Connection }=require("tedious");constconnection=newConnection({server: "(localdb)\\MSSQLLocalDB",// required by tedious but not used when a connector is givenauthentication: {type: "default",options: {userName: "…",password: "…"}},options: {encrypt: false,database: "master",connector: localDbConnector("MSSQLLocalDB"),// from above},});connection.connect((err)=>{/* … */});
Don't set options.instanceName: tedious would query SQL Browser before calling the connector. No port is needed.
Why the connector looks like this
Looking up the pipe costs two process spawns (about 150 ms on a running instance). If your pool opens many connections at once you can share one in-flight lookup between them; avoid caching the result for longer, for the reason above.
SqlLocalDB start exits 0 even when the instance doesn't exist, hence the check on info's output.
The abort handling is deliberate. tedious passes an AbortSignal (the connectTimeout, or connection.close()) as the third argument. A connector that ignores it isn't covered by connectTimeout (a connector that never settled left connect() hanging, with no callback in my 20 s test). On the other hand, killing SqlLocalDB.exe mid-start (what passing { signal } to execFile does) left an orphaned sqlservr.exe for me, and later starts failed with "SQL Server process failed to start" until I killed that process manually. The connector above stops waiting but lets the start finish. With a 200–300 ms connectTimeout against a stopped instance it gave ETIMEOUT on time, the instance finished starting in the background, and the next connect worked.
Timing: the first start of a newly created instance took about 10 s; starting an existing stopped instance and connecting took about 2.5 s. The default 15 s connect timeout is enough, but a first run on a slow machine could get close.
Lifecycle:SqlLocalDB start launches a per-user sqlservr.exe that is not a child of your process and outlives it. It stayed up while a connection was open (I held one idle for 7 minutes), and stopped itself about 5 minutes after the last connection closed (measured: 304 s). SqlLocalDB.exe stop <instance> stops it explicitly.
Files: a CREATE DATABASE without FILENAME puts the files in the instance's InstanceDefaultDataPath, which was my user profile folder, not the instance's own folder.
Instances:SqlLocalDB.exe info lists them; SqlLocalDB.exe create MyInstance 17.0 creates one (re-running create on an existing instance is harmless). If several LocalDB versions are installed, the SqlLocalDB.exe first on PATH managed a newer-version instance fine in my test.
msnodesqlv8 connected to LocalDB with Windows authentication using a connection string such as Driver={ODBC Driver 17 for SQL Server};Server=(localdb)\MyInstance;Database=master;Trusted_Connection=yes.
tedious 20.3.8, mssql 12.7.11, Node 24.15.0, Windows, SQL authentication. The mssql example above ran as written against the default MSSQLLocalDB instance (SQL Server 2019) and against SQL Server 2025 LocalDB. Also checked: a 2 MB parameter and a 300 KB result through the pipe, a new connection after the instance stopped and restarted, and connectTimeout against a stopped instance. Not tested: Windows authentication through tedious, shared instances ((localdb)\.\Name), other tedious/mssql versions.
Edited: removed an unnecessary port option and changed the abort handling (see above).
Activity
arthurschreiber commentedon Dec 7, 2015
I guess you're talking about SQL Server Express LocalDB? If yes, this should be supported, as it's basically a slimmed down version of SQL Server. But no guarantees, as I never used that version before.
Did connecting to your LocalDB instance work before?
beautifulcoder commentedon Dec 7, 2015
I use it for testing, here is the info on it:
I am using this to connect to it:
arthurschreiber commentedon Dec 8, 2015
Ah, ok, I now understand your issue.
tediouscurrently does not know how to connect to a SQLServer instance through a named pipe. Nodejs supports named pipes on windows (only local named pipes), but correct handling for this was never implemented.Another issue is that from my understanding, native TDS drivers from microsoft will start your localdb instance if it's not already running.
tediouswill never support this.So overall, I stand corrected. As-is,
tediouswon't be able to connect to your LocalDB instance.beautifulcoder commentedon Dec 8, 2015
Ah, awesome to know. Sounds like TDS solves a specific problem which is great. I agree that named pipes are another issue altogether.
duwoodaes commentedon May 17, 2016
Thanks for the information posted here. I too am looking to implement a solution where I would need to connect to localdb.
rcarubbi commentedon Mar 10, 2018
Did anyone solve this question with another approach?
fowl2 commentedon Oct 26, 2026
For anyone landing here, tedious can't resolve
(localdb)\Instanceitself, but it can connect to LocalDB if you hand it the instance's named pipe via theconnectoroption (tedious ≥ 16.1.0). This works withmssqltoo, which is the easier route if that's what you use.With
mssql(Windows only,SqlLocalDB.exemust be onPATH; top-levelawaitshown for brevity):Things worth knowing:
server: "(localdb)", not"(localdb)\\MSSQLLocalDB", and don't use aServer=(localdb)\…connection string.mssqlturns anything after the backslash into an instance name, which makes tedious look up a port through SQL Browser (LocalDB has none) before it ever calls the connector. Pass the instance name to the connector instead, as above.sqlcmd -S "(localdb)\MSSQLLocalDB" -E -Q "CREATE LOGIN dev WITH PASSWORD = '…', CHECK_POLICY = OFF; ALTER SERVER ROLE sysadmin ADD MEMBER dev"Any tool that can connect with Windows authentication (SSMS, Azure Data Studio, PowerShell's
Invoke-Sqlcmd) works equally well. If you need Windows authentication in your app, usemssql/msnodesqlv8instead.encrypt: falseis required, otherwise the connection fails with "Server did not negotiate encryption".ENOENT \\.\pipe\LOCALDB#…after your app has been idle.Plain tedious (without mssql)
Don't set
options.instanceName: tedious would query SQL Browser before calling the connector. Noportis needed.Why the connector looks like this
SqlLocalDB startexits 0 even when the instance doesn't exist, hence the check oninfo's output.AbortSignal(theconnectTimeout, orconnection.close()) as the third argument. A connector that ignores it isn't covered byconnectTimeout(a connector that never settled leftconnect()hanging, with no callback in my 20 s test). On the other hand, killingSqlLocalDB.exemid-start (what passing{ signal }toexecFiledoes) left an orphanedsqlservr.exefor me, and later starts failed with "SQL Server process failed to start" until I killed that process manually. The connector above stops waiting but lets the start finish. With a 200–300 msconnectTimeoutagainst a stopped instance it gaveETIMEOUTon time, the instance finished starting in the background, and the next connect worked.SqlLocalDB startlaunches a per-usersqlservr.exethat is not a child of your process and outlives it. It stayed up while a connection was open (I held one idle for 7 minutes), and stopped itself about 5 minutes after the last connection closed (measured: 304 s).SqlLocalDB.exe stop <instance>stops it explicitly.CREATE DATABASEwithoutFILENAMEputs the files in the instance'sInstanceDefaultDataPath, which was my user profile folder, not the instance's own folder.SqlLocalDB.exe infolists them;SqlLocalDB.exe create MyInstance 17.0creates one (re-runningcreateon an existing instance is harmless). If several LocalDB versions are installed, theSqlLocalDB.exefirst onPATHmanaged a newer-version instance fine in my test.Driver={ODBC Driver 17 for SQL Server};Server=(localdb)\MyInstance;Database=master;Trusted_Connection=yes.serverstring even with a connector (serverandportproperties are required when using the customconnectorfactory method #1541);mssqlsupplies one.What I tested
tedious 20.3.8, mssql 12.7.11, Node 24.15.0, Windows, SQL authentication. The mssql example above ran as written against the default
MSSQLLocalDBinstance (SQL Server 2019) and against SQL Server 2025 LocalDB. Also checked: a 2 MB parameter and a 300 KB result through the pipe, a new connection after the instance stopped and restarted, andconnectTimeoutagainst a stopped instance. Not tested: Windows authentication through tedious, shared instances ((localdb)\.\Name), other tedious/mssql versions.Edited: removed an unnecessary
portoption and changed the abort handling (see above).drafted by an LLM, reviewed by me