Node.js Driver release notes for 2026¶
This article contains the release notes for the Node.js Driver, including the following when applicable:
- Behavior changes
- New features
- Customer-facing bug fixes
Snowflake uses semantic versioning for Node.js Driver updates.
See Node.js Driver for documentation.
Version 4.0.0-beta.0 (November 12, 2026)¶
Initial public preview release of the Node.js Driver built on the Universal Core. This is a new major version line, published under the existing snowflake-sdk package name with the npm beta tag. The npm latest tag still points to version 3.x, so install this version explicitly with npm install snowflake-sdk@beta. Version 3.x remains the version recommended for production.
New architecture and installation¶
Version 4 is a full rewrite. Most of the driver is now written in Rust and compiled into a native .node addon, which makes the driver much faster, uses less disk space, and reduces the driver’s other npm dependencies to two. The driver and Universal Core source are published in the Snowflake drivers repository (https://github.com/snowflakedb/drivers) on GitHub.
The public API is the same, except for the breaking changes listed in this release note. Because this is a new codebase, expect some small differences in behavior, including different error messages and codes. If your code checks error text, test it before you upgrade.
npm installs the prebuilt addon for your platform as the optional dependency @snowflake/sdk-core-<platform>. Prebuilt addons are available for the following platforms:
- macOS: arm64 and x64
- Linux: arm64 and x64 (glibc and musl)
- Windows: arm64, x64, and x86
You might need to adjust your setup in the following cases:
- If you install with
--omit=optional, the addon isn’t installed. - If you run
npm installon one platform and deploy to another, for example, from macOS to a Linux container or AWS Lambda, runnpm installon the target platform instead. - If you bundle your app with webpack, esbuild, or a similar tool, mark
snowflake-sdkas external. - If you use a platform that isn’t listed, you must build the addon from source with Rust.
Known issues¶
The following areas are still in progress, so their behavior might change in later beta releases before the 4.x general availability release:
- FIPS mode is still in progress. The native library can be built for FIPS, but the published prebuilt addons aren’t FIPS builds, so
snowflake.getFipsStatus()returns{ isFips: false }for them. The way to set up FIPS mode in 4.x isn’t decided yet. Node.js FIPS settings, such as the--enable-fipsand--force-fipsflags orcrypto.setFips(), have no effect on the driver, because the driver performs cryptography in its native library instead of the built-incryptomodule. - Errors are still a work in progress. Error classes,
codevalues, and messages might change, and some errors don’t have acodeyet. Avoid relying on the exact error text. - TypeScript types and their JSDoc aren’t final. Some methods and options have short or missing descriptions, and some types might still change.
- Some behavior still differs from 3.x and is being reviewed, mainly in the following areas:
- Query cancellation and long-running queries
- Reading large results
- Timeouts and retries
- External browser, Okta, OAuth, and workload identity authentication
- Proxy settings
- Token caching and custom credential managers
- Performance is still being tuned. The driver is already faster than 3.x in most cases, and more improvements are planned.
- Some features have gaps in test coverage. These gaps are being reviewed, and tests are being added in upcoming beta releases.
Breaking changes¶
Note
This list of breaking changes isn’t final. Entries might be added or removed based on feedback from the beta.
General changes¶
- Changed the minimum supported Node.js version from 20 to 22, because Node.js 20 has reached end of life. Upgrade to Node.js 22 or later before you update the driver.
- Changed queries to fail when a
VARIANT,OBJECT,ARRAY, orMAPvalue containsNaN,Infinity, orundefined, which aren’t valid JSON. Snowflake returns these values by default, when the STRICT_JSON_OUTPUT parameter isFALSE. For example,OBJECT_CONSTRUCT('a', 'NaN'::FLOAT)returns{"a": NaN}, andARRAY_CONSTRUCT(1, NULL, 2)returns[1, undefined, 2]. The driver now parses these values only withJSON.parse(). Previously, it evaluated values that weren’t valid JSON as JavaScript code. This evaluation was removed as a safety precaution and becauseJSON.parse()is much faster. To read such values, do one of the following:- Set
STRICT_JSON_OUTPUTtoTRUE. Snowflake then returnsnullinstead ofundefined, and the strings"NaN"and"Infinity". - Pass your own
jsonColumnVariantParsertosnowflake.configure().
- Set
- Changed the driver to no longer honor most Node.js runtime flags, environment variables, and global settings of the Node.js
tls,https,dns, andcryptomodules, because the driver doesn’t use these modules. For example, flags such as--use-openssl-ca,--openssl-config,--tls-min-v1.3,--tls-cipher-list, and--dns-result-order, and code such astls.DEFAULT_MIN_VERSION = 'TLSv1.3'ordns.setDefaultResultOrder('ipv4first'), have no effect on the driver. Only two Node.js environment variables still work:NODE_TLS_REJECT_UNAUTHORIZED=0turns off TLS certificate checks.NODE_EXTRA_CA_CERTSadds the certificates from the specified file to the list of trusted certificates.
Removed APIs and options¶
- Removed OCSP checks. Snowflake drivers now check for revoked certificates with certificate revocation lists (CRLs), because OCSP often caused connection failures and many certificate authorities are dropping OCSP support. CRL checks are off by default, matching the OCSP default since version 3.4.0. To turn them on, set the
certRevocationCheckModeconnection option toENABLED(replaces OCSP fail-closed mode) orADVISORY(replaces OCSP fail-open mode). The following APIs were removed:- The
disableOCSPChecksandocspFailOpenoptions ofsnowflake.configure(). - The
useConnectionConfigProxyForOCSPconnection option. - The
connection.setupOcspPrivateLink()method. - The
snowflake.ocspModesexport and theOcspModestype.
- The
- Removed the undocumented
toStringSf()andgetFormat()methods from theBufferreturned forBINARYcolumns, which is now a plainBuffer. To get the value as text, usebuffer.toString('hex').toUpperCase()orbuffer.toString('base64'). - Removed the undocumented
BRvalue ofSOURCE_COMPRESSIONinPUT. To upload Brotli-compressed files, use the documentedBROTLIvalue instead. - Removed the following connection options:
clientRequestMFAToken. MFA token caching is now controlled byclientStoreTemporaryCredential.disableConsoleLogin. This option isn’t needed because Snowflake already chooses the right login page. External browser authentication always opens the URL that Snowflake returns, as it did with the default valuetrue. If the account has theENABLE_IDENTIFIER_FIRST_LOGINparameter turned on, Snowflake returns its login page, where the user selects one of the account’s identity providers. Otherwise, the account can have only one identity provider, and the browser goes directly to it.region, which was deprecated. Sethostto the full host name of your account, or setaccessUrl, instead.clientConfigFile, and the easy logging feature that it configured. The driver no longer readssf_client_config.json, whether its path comes from this option or theSF_CLIENT_CONFIG_FILEenvironment variable, or the file is in the driver or home directory. If you used this file, the driver no longer writes those logs. To set the log level and log file, use thelogLevelandlogFilePathoptions ofsnowflake.configure().oauthHttpAllowed, which was deprecated and intended only for tests.oauthTokenRequestUrlmust still usehttps://, buthttp://is now accepted without any option when the host islocalhost,127.0.0.1, or::1, for example, for a local mock server.serviceName. The service name is an internal session value that applications shouldn’t set.includeRetryReason. Retried requests always include the HTTP status code that caused the retry, as they did by default, because Snowflake uses this status code to find out why requests are retried.validateDefaultParameters. TypeScript already reports a misspelled option name at compile time, and the driver now always logs a warning for an unknown option and ignores it.forceStageBindError. This option made array binds fail on purpose and was intended only for the driver’s own tests.gcsUseDownscopedCredential. Snowflake already uses downscoped credentials forPUTandGETon Google Cloud Storage by default, so this option had no effect.
- Removed the experimental
enableExperimentalMultipartUploadsoption ofsnowflake.configure().PUTandGETnow always transfer large files in parts on Amazon S3 and Azure stages. For details, see the multipart transfer entry under New features and updates. - Removed the following methods:
connection.getServiceName(). The service name is an internal session value that applications shouldn’t depend on.statement.getStatementId(), which was deprecated. This method returned the same query ID asstatement.getQueryId(), so callgetQueryId()instead.statement.fetchRows(), which was deprecated. Usestatement.streamRows()instead, which returns the same rows as aReadablestream. Read the stream withfor await (const row of statement.streamRows()), or replace theeachcallback with the'data'event and theendcallback with the'end'and'error'events.
- Removed the following types and type members:
- The
FileAndStageBindStatementtype. ItshasNext()andNextResult()methods moved toRowStatement, which every query returns. These methods step through the results of a multi-statement query and aren’t related to files or stages, so declaring them only onFileAndStageBindStatementwas a mistake in the types. For a single statement,hasNext()returnsfalse. If your code usesFileAndStageBindStatement, replace it withRowStatement. - The options that apply only to
connection.execute()fromconnection.fetchResult()andconnection.getResultsFromQueryId(). Their options were typed as{ queryId: string } & Partial<StatementOption>, but most of these options, such asbinds,parameters,requestId, andasyncExec, had no effect. They’re now typed as the newFetchResultOptionstype, with onlyqueryId,complete,streamResult,rowMode, andfetchAsString. If your TypeScript code passes other options, remove them. ThesqlTextoption was also removed. If you need the SQL text, keep it in your own code. - The
excludeGuidandqueryIdfields of theStatementOptiontype.connection.execute()never used them, so setting them had no effect. If your TypeScript code sets them, remove them. To get the result of an earlier query by its ID, useconnection.getResultsFromQueryId({ queryId }).
- The
- Removed the following undocumented APIs, which were never intended to be public and weren’t part of the TypeScript types:
- The
snowflake.STRING,snowflake.BOOLEAN,snowflake.NUMBER,snowflake.DATE,snowflake.OBJECT,snowflake.ARRAY,snowflake.MAP, andsnowflake.JSONconstants. No public API used them. - The
connection.isTokenValid()method. - The
connection.heartbeat()andconnection.heartbeatAsync()methods. To check that a connection still works, useawait connection.isValidAsync(), which sends the same heartbeat request. To keep a session alive, set theclientSessionKeepAliveconnection option. - The
getFileMetadata()method on the statement returned for aPUTorGETcommand. This method returned the raw response that Snowflake sent for the command. To see what happened to each file, read the result rows, for example, in thecompletecallback. - The
getCurrentDatabaseProvider()method on the object returned bystatement.getSessionState(). This method always returnednull. - The
sessionToken,masterToken,sessionTokenExpirationTime, andmasterTokenExpirationTimeoptions ofsnowflake.createConnection(). These options weren’t part ofConnectionOptions. To reuse a session, useconnection.serialize()andsnowflake.deserializeConnection().
- The
Data type changes¶
- Changed
TIMESTAMP_TZ,TIMESTAMP_LTZ, andTIMEvalues with a zero UTC offset to show the offset asZinstead of+0000,+00:00, or+00when they’re returned as text, for example,2024-01-15 10:30:00.000 Z. This format matches the text that Snowflake returns forTO_CHARand::VARCHAR. For timestamps, this change applies tofetchAsString: ['Date']andtoJSON(), and therefore also toJSON.stringify()of rows.TIMEvalues are always returned as text, so for them, this change applies wheneverTIME_OUTPUT_FORMATcontainsTZH.new Date()reads both forms the same way. If your code checks the offset text with a regular expression or a strict format, also acceptZ. - Changed integer columns to return a native JavaScript
BigIntinstead of abig-integerobject when thejsTreatIntegerAsBigIntconnection option or the JS_TREAT_INTEGER_AS_BIGINT session parameter is enabled.BigIntis built into JavaScript and doesn’t need an extra package. Both types hold the same values and work mostly the same way, butbig-integeradds its own helper methods. If you use these methods, for example,.equals(),.add(), orBigInteger.isInstance(), switch toBigIntoperators such as===and+, and totypeof value === 'bigint'. - Changed
VECTORcolumns to return an array of numbers, such as[1.5, 2.5, 3.5], instead of the text sent by the server, such as'[1.500000,2.500000,3.500000]'. If your code parses that text, use the array directly. To get a string instead, add'Number'tofetchAsString. The array is then returned as JSON text, such as'[1.5,2.5,3.5]', and a NULL value as'NULL', the same as for other numbers.
Connection changes¶
- Changed login tokens to be cached by default. The
clientStoreTemporaryCredentialconnection option now defaults totrueand also controls MFA token caching, replacing the removedclientRequestMFATokenoption. External browser, OAuth authorization code, and MFA authentication now reuse a cached token, so users are asked to log in less often. MFA tokens are cached only when your account allows it.- Tokens are stored in the system keyring when one is available, such as the macOS Keychain, Windows Credential Manager, or a Linux keyring.
- Without a keyring, for example, on headless Linux or in CI, tokens are stored in a JSON file in the
SF_TEMPORARY_CREDENTIAL_CACHE_DIRdirectory. WhenSF_TEMPORARY_CREDENTIAL_CACHE_DIRisn’t set, the file is stored in$XDG_CACHE_HOME/snowflakeor~/.cache/snowflake. - If none of these directories can be used, the driver logs a warning and logs in without caching.
- To turn off caching, set
clientStoreTemporaryCredential: false.
- Changed
snowflake.createConnection()to no longer check the values of connection options. A missing or invalid option now failsconnection.connect()orconnection.connectAsync()instead. Connecting is the step that reads the connection profile and key files and logs in, so all errors about your settings come from one place. If you wrapcreateConnection()intry/catchto handle missing or invalid options, handle these errors when you connect instead: in theconnect()callback, or withtry/catcharoundawait connection.connectAsync(). - Changed
connection.connectAsync()to report every error by rejecting the returned promise, and removed its callback parameter. Previously, the promise rejected only for some setup errors. Login errors, such as a wrong password, went only to the callback, and the promise still resolved. A callback passed toconnectAsync()is now never called, so handle errors withtry/catcharoundawait connection.connectAsync()or with.catch(). - Changed the
resultPrefetchconnection option to be an alias for theCLIENT_PREFETCH_THREADSsession parameter, which sets the number of result chunks that the driver downloads at the same time. Snowflake now validates the value. Without this option, the session uses its ownCLIENT_PREFETCH_THREADSvalue, which is 4 unless it’s set on the user or account. Previously, the driver validated the value itself and downloaded up toresultPrefetch + 1chunks at once, 3 by default. - Changed connecting to fail with an
InvalidParameterErrorwhenauthenticatorisn’t a supported value, for example, because of a typo. Previously, the driver logged a warning and fell back to password authentication, so the typo could go unnoticed when apasswordwas also set. - Changed connecting to fail with an
InvalidParameterErrorwhenworkloadIdentityProvider,workloadIdentityAzureEntraIdResource,workloadIdentityImpersonationPath, orworkloadIdentityAwsUseOutboundTokenis set butauthenticatorisn’tWORKLOAD_IDENTITY. Previously, the driver ignored these options and logged in with the other authenticator, which hid a mistake in the connection settings. Remove these options, or setauthenticatortoWORKLOAD_IDENTITY. - Changed
connection.isUp()to returnfalseonly when the session has ended: the login expired, or Snowflake reports that the session is closed or no longer exists. Previously, it also returnedfalsewhen Snowflake refused to renew the session for any other reason, for example, because the account no longer allows the client’s IP address.isUp()doesn’t contact Snowflake. To check whether a connection can still run queries, useawait connection.isValidAsync(), which sends a request to Snowflake and also returnsfalsein these cases.
Query execution changes¶
- Changed
connection.execute()to fail with aClientErrorwith code407001when it’s called while the connection is still logging in. Previously, the driver held such queries and ran them after the login finished. The new driver doesn’t hold queries. Wait until the connection is established before you run queries, for example, withawait connection.connectAsync()or inside theconnect()callback. - Changed the TypeScript types of
statement.getQueryId(),getRequestId(),getSqlText(),getNumRows(), andgetColumn()to includeundefined, because these methods returnundefinedin some cases, as they did before: for example, while the query is running, after it fails, or for a column that doesn’t exist. They’re now typed asgetQueryId(): string | undefined,getRequestId(): string | undefined,getSqlText(): string | undefined,getNumRows(): number | undefined, andgetColumn(columnIdentifier: string | number): Column | undefined, and their descriptions say when they returnundefined. The returned values didn’t change, so where TypeScript now reports an error but your code knows that the value is set, for example, in thecompletecallback of a successful query, check forundefinedor add!. - Changed the
completecallback ofconnection.execute()to receiveundefinedas itsrowsargument whenasyncExecistrue. Previously, the driver incorrectly put a{ queryId }object inrows:rowsis typed as an array of rows orundefined, and an async query has no rows yet. The query ID has always been available fromstatement.getQueryId(), so use that method instead. - Changed
connection.execute()withdescribeOnly: trueto fail for a multi-statement query. Previously, it succeeded but returned only one placeholder column namedmultiple statement executioninstead of the columns of your statements, because Snowflake doesn’t describe the statements of a multi-statement query. To get column metadata, rundescribeOnlyon each statement separately. - Changed
GETto fail when no file in the stage matches the path orPATTERN. Previously, it returned an empty result and downloaded nothing, which also hid a wrong path. If aGETin your code can match no files, catch the error, or runLISTwith the same path andPATTERNfirst. - Changed
connection.getQueryStatus()andconnection.getQueryStatusThrowIfError()to return'NO_DATA'instead of the undocumented'NO_QUERY_DATA'when Snowflake has no status for the query ID. Snowflake returns no status both for a query that hasn’t started yet and for a query ID that doesn’t exist, so the driver can’t tell these cases apart.'NO_DATA'counts as still running, so a loop that waits whileconnection.isStillRunning(status)istruekeeps waiting for a query ID that doesn’t exist. If your code can pass such an ID, limit how long it waits.
Error and configuration changes¶
- Changed the errors that the driver reports for missing or invalid connection options to be an
InvalidParameterErrorwithout acode. The 3.x driver checked each option in its own way, so its errors weren’t consistent: most were anInvalidParameterErroror aMissingParameterErrorwith a code such as404008, but some were a plainErrorwith no code. The new driver checks all options in one shared step, so it can no longer give each problem its own code. Instead, the errormessagenames every option that’s missing or invalid. If your code checkserror.codeorMissingParameterError, checkerror.name === 'InvalidParameterError'instead. - Changed the type of the
xmlParserConfigoption ofsnowflake.configure()toX2jOptionsfromfast-xml-parser.attributesGroupName: nullno longer compiles in TypeScript. UseattributesGroupName: falseinstead, which works the same way.
New features and updates¶
- Added support for connection profiles in the
config.tomlfile, the configuration file that other Snowflake tools also use. Profiles go under[connections.<name>], and thedefault_connection_namekey sets the profile that’s used whencreateConnection()gets no options. - Added the
connectionNameconnection option, which selects a connection profile by name. You can pass other connection options with it. The driver starts from the profile and replaces only the options that you pass, for example, to use a differentwarehousethan the profile sets. Without this option, a profile is read only whencreateConnection()gets no options, as before. - Added the
proxyconnection option, which sets the proxy as one URL, for example,http://user:password@proxy.example.com:8080. The scheme can behttporhttpsand defaults tohttp. Percent-encode special characters in the user name or password, for example,@as%40. WhenproxyHost,proxyPort,proxyProtocol,proxyUser, orproxyPasswordis also set, it replaces the matching part of the URL. - Added the
protocolandportoptions toConnectionOptions. These options set the scheme and port used withhost, and now apply to every request, including external browser and Okta authentication, which previously always usedhttpson the default port. - Added support for a base64-encoded DER key in the
privateKeyconnection option. Previously, only a PEM string was accepted. - Added support for
workloadIdentityImpersonationPathwith theAZUREworkload identity provider. The path must contain exactly one service principal client ID. - Added
sqlState'28000'to errors for logins that Snowflake rejects because of wrong credentials, such as a wrong password or an invalid key-pair token. - Added
isDecfloat(),isIntervalYearMonth(),isIntervalDayTime(), andisVector()toColumn, for data types that had no such check. - Added the
SnowflakeDateexport, the class of the values returned forDATEandTIMESTAMPcolumns. It extendsDateand addsgetEpochSeconds(),getNanoSeconds(),getScale(),getTimezone(), andgetFormat(). These methods existed before but had no types, so TypeScript code can now use them after avalue instanceof SnowflakeDatecheck instead of a hand-written type. - Added the
SessionStatetype.statement.getSessionState()now returnsSessionState | undefinedinstead ofobject | undefined, so TypeScript code can callgetCurrentDatabase(),getCurrentSchema(),getCurrentWarehouse(), andgetCurrentRole()without a cast. Each method returnsstring | null. - Added the
CustomCredentialManagertype. ThecustomCredentialManageroption ofsnowflake.configure()is now typed asCustomCredentialManagerinstead ofobject. This type declares theread,write, andremovemethods that the driver already required, so TypeScript reports a manager without them at compile time, instead ofconfigure()throwing an error at runtime. - Added
snowflake.getFipsStatus()and theFipsStatustype. The method is typed asgetFipsStatus(): FipsStatus, whereFipsStatusis{ isFips: boolean }, and reports whether the driver’s native library is compiled for FIPS. - Added support for all
fast-xml-parseroptions in thexmlParserConfigoption ofsnowflake.configure(). Previously, the driver used onlyignoreAttributes,alwaysCreateTextNode,attributeNamePrefix, andattributesGroupName, and ignored any other option. - Added multipart uploads to
PUTand multipart downloads toGETon Amazon S3 and Azure stages. Large files now transfer faster, and when a request fails, the driver repeats only that part instead of the whole file. This behavior is always on, so the experimentalenableExperimentalMultipartUploadsoption ofsnowflake.configure()was removed. Multipart transfers work as follows:- A file is split into parts when its size, after compression and encryption, is at least the limit that Snowflake sends for each
PUTandGETcommand. This limit is currently 200 MiB. Smaller files are still sent in one request. - Each part is 8 MiB. For very large files, the parts are bigger, so the file stays within the limit on the number of parts: 10,000 on Amazon S3 and 50,000 on Azure.
- Parts are sent in parallel. The
PARALLELoption ofPUTandGETsets how many requests run at once for the whole command. A single file uses at most 16 requests at once. The driver reads the file one part at a time, so it never holds the whole file in memory. - When an upload part fails, for example, because the stage credentials expired, the driver retries only that part. If an Amazon S3 upload still fails, the driver cancels it, which deletes the parts already sent.
- On Google Cloud Storage,
PUTintentionally sends each file in one request, because one request is much faster than a multipart upload on Google Cloud Storage. - In version 3.x, with
enableExperimentalMultipartUploadsturned on, uploads were split starting at 64 MiB, parts were sent one at a time, and Google Cloud Storage uploads were also split into parts.
- A file is split into parts when its size, after compression and encryption, is at least the limit that Snowflake sends for each
Changes¶
- Changed the format of the string returned by
connection.serialize(). As documented, the format can change between driver versions, so pass the string tosnowflake.deserializeConnection()only on the same driver version. If several processes share serialized connections, upgrade them all at the same time. - Removed the client-side length check for the
queryTagconnection option. Snowflake still checks the value when you connect, so an invalidqueryTagcan still fail whenconnect()orconnectAsync()is called. - Removed the format check for the
applicationconnection option. Any string is now accepted, because Snowflake doesn’t check this value. - Changed how
ISAis reported in telemetry to be consistent with other drivers. - Changed when
PLATFORMis reported in telemetry, so it no longer blocks the first connection request.
Bug fixes¶
Bug fixes that might affect your code¶
The following fixes change a value, error, or type that the driver returns. If your code works around the old behavior, update it.
- Fixed
fetchAsString: ['JSON']returning onlyVARIANTcolumns as strings. It now also coversOBJECT,ARRAY, andMAPcolumns. This includesFILEcolumns, andGEOGRAPHYandGEOMETRYcolumns in the default GeoJSON format, because theirgetType()is'object'. Their values are returned as the JSON text sent by Snowflake, such as'{\n "key": "value"\n}', and NULL values as'NULL'unlessrepresentNullAsStringNullisfalse. If your code reads these columns as objects, parse them withJSON.parse(). - Fixed
TIMEcolumns returning the string'NULL'instead ofnullfor NULL values. All other types already returnednull. If your code checks aTIMEvalue for'NULL', check fornullinstead. - Fixed
FLOATcolumns returningNaNfor the valuesinfand-inf. They now returnInfinityand-Infinity, so they can be distinguished from a realNaN. If your code finds these values withNumber.isNaN(), use!Number.isFinite()instead. - Fixed the
BLOCKEDquery status being treated as a failure. A blocked query hasn’t finished and can still succeed, soisStillRunning('BLOCKED')now returnstrueandisAnError('BLOCKED')returnsfalse.getQueryStatusThrowIfError()no longer throws an error for this status, andgetResultsFromQueryId()waits for the query to finish instead of failing. If your code handlesBLOCKEDas a failure, remove that handling. - Fixed
statement.getNumUpdatedRows()returning-1forCOPY INTO <table>. It now returns the number of rows loaded. If your code checks for-1afterCOPY INTO, use the returned number instead. - Fixed
Column.isObject()andColumn.isArray()returningfalseforOBJECTandARRAYcolumns, even thoughgetType()returned'object'or'array'. Code that branches on these methods now takes theOBJECTorARRAYbranch for these columns. - Fixed
connection.getQueryStatusThrowIfError()rejecting with code-1when the query failed on the server. The error now has the query’s Snowflake error code, for example,'002003'. If your code checks for code-1, check the Snowflake error code instead. - Fixed
pool.acquire()andpool.use()rejecting with a plainErrorwhen a pooled connection fails to connect. They now reject with the original connection error, including itsname,code, andsqlState. If your code checks the message of that error, check itsnameorcodeinstead. - Fixed
targetSizeinPUTresults not matching the size of the file stored in the stage. On stages with client-side encryption, it was the size before encryption. It’s now the size after encryption, which is slightly larger. - Fixed
Column.getScale()andColumn.getPrecision()being typed to returnnumber. They returnnullfor columns that have no scale or precision, such asTEXTcolumns. They’re now typed asgetScale(): number | nullandgetPrecision(): number | null, so TypeScript might ask you to handlenullwhere you use these values.
Other bug fixes¶
- Fixed
representNullAsStringNullset on one connection also applying to every other connection in the same process. - Fixed the missing
statusargument in theconnection.isAnError()types. The method is now typed asisAnError(status: QueryStatus): boolean. - Fixed
connection.getQueryStatus()andconnection.getQueryStatusThrowIfError()being typed to returnPromise<string>, which meant that TypeScript code had to cast the result before passing it toisStillRunning()orisAnError(). They’re now typed asgetQueryStatus(queryId: string): Promise<QueryStatus>andgetQueryStatusThrowIfError(queryId: string): Promise<QueryStatus>. - Fixed the
Bindtype missingDate. The driver has always acceptedDatevalues inbinds, but the type didn’t list it. - Fixed a
QUERY_TAGpassed in theparametersoption ofconnection.execute()being replaced by thequeryTagconnection option. The statement’sQUERY_TAGnow applies to that query, and later queries still use the connection’squeryTag. - Fixed
ALTER SESSION SET CLIENT_STAGE_ARRAY_BINDING_THRESHOLDhaving no effect when thearrayBindingThresholdconnection option is set. The option now sets only the starting value of the session parameter, so the value that’s set last decides when binds are uploaded to a stage. - Fixed the
optionsargument ofsnowflake.configure()being typed as optional. A call without arguments always threw aTypeError. The method is now typed asconfigure(options: ConfigureOptions): void, so TypeScript reports this mistake at compile time. - Fixed
snowflake.configure()dropping an earliercustomLoggeroradditionalLogToConsolevalue when a later call sets another logging option, such aslogLevel. Logging options now keep their earlier values, like every otherconfigure()option, and a call that sets onlyadditionalLogToConsolenow takes effect. - Fixed
snowflake.deserializeConnection()ignoring theclientSessionKeepAliveoption. - Fixed
PUTfailing with aTypeErrorwhenSOURCE_COMPRESSIONisBROTLI,AUTO_DETECT, orNONE. - Fixed
sourceCompressioninPUTresults always beingnull. It now shows the compression type of the source file, such as'NONE'or'GZIP'. - Fixed
PUTfailing when the source path starts with~or contains the?wildcard.~now means your home directory, and?matches any single character.
Version 3.4.1 (October 26, 2026)¶
New features and updates¶
- Added the HTTP status of the failed storage request, such as
(HTTP 502), toPUTandGETerrors from S3, Azure, and Google Cloud Storage stages. The HTTP status helps you diagnose failures when the storage response can’t be read, such as an S3Deserialization errorcaused by a proxy that returns a plain-text error.
Bug fixes¶
- Fixed concurrent S3 file transfers through a proxy failing with
socket hang upbecause finishing one transfer closed the proxy connections that other transfers were still using. - Fixed
GETfrom S3 and Azure stages failing withTypeError: Cannot read properties of null (reading 'encryptionMetadata')when the file metadata request failed but the download itself succeeded (for example, when an HTTPS proxy rejected the TLS handshake). TheGETnow fails with the underlying error before decrypting the file. - Fixed a failed
GETof an encrypted file leaving the still-encrypted download in the local directory when the file metadata request failed or the file couldn’t be decrypted. When the metadata request fails, the error now includes its HTTP status. - Fixed
PUTfailing withUnknown error during PUT of fileafter the file was uploaded, when the follow-up request that checks whether the file is on the stage failed. - Fixed
GETfrom Google Cloud Storage stages hanging indefinitely when the connection broke during the download. The driver now retries the download. - Fixed queries failing with
Unable to perform operation using terminated connection.(407002) when the expired session couldn’t be renewed. These queries now fail with the server error that explains the cause, for example,390114when the authentication token expired after the connection was idle for too long. - Fixed a late session-expired response starting another session renewal on a connection that a failed renewal had already closed.
Version 3.4.0 (September 30, 2026)¶
Security fixes¶
- Hardened
EXTERNALBROWSERauthentication by binding the local callback listener to127.0.0.1and rejecting requests whoseOriginheader doesn’t match the connected Snowflake account. The listener now ignores incomplete or unrelated requests instead of ending the login.
New features and updates¶
- Added the
workloadIdentityHostconnection option that overrides the STS host used by AWS workload identity flows, so AWS partitions unknown to the driver can be reached. When this option isn’t set, the STS host is derived from the AWS region. - Bumped the
tomldependency to version 5.0.0.
Changes¶
- Turned OCSP off by default and marked OCSP support as deprecated. OCSP support will be removed in the next major release. Use CRL validation (
certRevocationCheckMode) instead.- To keep using OCSP, call
snowflake.configure({ disableOCSPChecks: false }),snowflake.configure({ ocspFailOpen: true })for fail-open, orsnowflake.configure({ ocspFailOpen: false })for fail-closed. If both options are provided in the same call,disableOCSPChecks: trueturns OCSP off regardless ofocspFailOpen. CRL still takes precedence whencertRevocationCheckModeis enabled. - Deprecated APIs: OCSP options (
disableOCSPChecks,ocspFailOpen,useConnectionConfigProxyForOCSP),connection.setupOcspPrivateLink(),ocspModes, and OCSP error codes.
- To keep using OCSP, call
Bug fixes¶
- Fixed failed
PUToperations reportingUnknown Error in uploading a fileinstead of the underlying storage error.
Version 3.3.0 (September 3, 2026)¶
Security fixes¶
- Restricted the
WORKLOAD_IDENTITYauthenticator to recognized Snowflake hosts (*.snowflakecomputing.cn,*.snowflakecomputing.cn, and*.snowflakecomputing.mil). To extend the list of allowed hosts, use theSNOWFLAKE_WIF_ALLOWED_HOST_SUFFIXESenvironment variable. - Improved OCSP response validation so that a response must correspond to the certificate being checked. Verification now selects the matching single response from the OCSP message instead of using the first one, and fails with
ERR_OCSP_RESPONSE_CERT_MISMATCHwhen none matches. This applies to both live checks and cached responses. - Fixed PrivateLink host detection using a substring match that could misclassify a host as a PrivateLink host.
- Changed cloud storage response logs to list header names instead of full header objects, which keeps header values out of the logs. Query strings are also trimmed from cloud storage URLs before they reach debug logs.
- Corrected the SAS token masking rule in debug logs and extended masking to cover the
X-Amz-CredentialandX-Amz-Security-TokenURL parameters and the S3 SSE-C customer-key header.
Version 3.2.0 (August 18, 2026)¶
Deprecations¶
- Marked
RowStatement.fetchRows()as deprecated. This method will be removed in the next major version. UsestreamRows()instead. - Removed the
getRowValue()andgetRowValueAsString()methods from theColumninterface. These methods required an internal row representation that is never exposed publicly, so calling them on user-visible rows always threw a runtime error.
New features and updates¶
- Improved CRL signature verification performance by about 100 times, from roughly 635 ms to roughly 6 ms per certificate revocation list in upstream testing. The driver now caches the raw CRL bytes and verifies the signature directly against them, instead of re-encoding the certificate list from the decoded CRL on every check. This is only on the connection path when certificate revocation checking is enabled.
Bug fixes¶
- Fixed the TypeScript typing for
connection.fetchResult(), which incorrectly requiredsqlTextand omittedqueryId. - Fixed Azure PUT and GET file transfers failing on non-commercial Azure clouds.
- Fixed
compressFileWithGZIPcrashing the Node.js process with an unhandled stream'error'event when the source file for aPUTcan’t be read. - Fixed token cache key collisions in multi-account and multi-role scenarios.
Version 3.1.0 (July 9, 2026)¶
New features and updates¶
- Added the
workloadIdentityAwsUseOutboundTokenconnection option (defaultfalse) that switches AWS workload identity attestation to STSGetWebIdentityTokenJWTs. Snowflake recommends this method and might make it the default in a future release. - Added a
customLoggeroption tosnowflake.configure()to route the driver’s log messages through your own logger (for example, winston, pino, or OpenTelemetry) instead of the built-in file or console logging.
Bug fixes¶
- Reverted the unintentional breaking change from the 3.0.0 release that switched AWS workload identity attestation from SigV4
GetCallerIdentityto STSGetWebIdentityToken. AWS workload identity again defaults toGetCallerIdentity, and the new method is now opt-in with theworkloadIdentityAwsUseOutboundTokenconnection option. - Fixed Private Link OCSP proxy requests failing with
HTTP 405 Method Not Allowedfor certificates whose AIA OCSP URI contains a path component (for example,oneocsp.microsoft.com/ocsp). - Fixed Node.js 24 compatibility by removing usage of the deprecated
util.isStringmethod, and added logging where this previously caused a silent failure. - Fixed CRL validation failing with a
crl.tbsCertList.revokedCertificates is not iterableerror for CRLs that contain no revoked certificates. - Fixed an unnecessary second PUT (stage re-resolution) per file during GCS uploads when the server scopes upload credentials with an access token.
- Fixed key-pair authentication ignoring
privateKeyPassfor an inlineprivateKey, so encrypted private keys can now be passed directly, just like withprivateKeyPath.
Version 3.0.0 (June 17, 2026)¶
BCR (Behavior Change Release) changes¶
Beginning with version 3.0.0, the Node.js driver introduced the following breaking change:
- Dropped official support for Node.js version 18. The minimum supported Node.js version is now 20, and
engines.nodeis set to>=20. This release might still run on Node.js 18 for now, but Snowflake no longer tests against it and won’t investigate or fix Node 18-only issues. Treat Node 18 as unsupported and migrate to a current Node.js LTS version.
New features and updates¶
- Added the
browserResponseRendererconnection option to customize the HTML response shown in the browser afterEXTERNALBROWSERandOAUTH_AUTHORIZATION_CODEcallbacks. - Added the
tokenFilePathconnection option that reads the authentication token from a file when notokenis provided. - Added the
serverSessionKeepAliveconnection option that keeps the session alive on the server side whenconnection.destroy()is called. This option is useful when you want to close the local connection while keeping async queries running on the server.
Bug fixes¶
- Fixed global URL detection incorrectly truncating account names that contain “global” (for example,
myorg-global). - Fixed the
noProxyconnection option and theNO_PROXYenvironment variable not bypassing the proxy for Private Link connections. - Fixed interrupted streaming HTTP responses being treated as successful empty responses instead of errors, which could cause
streamRows()to hang silently on large result sets. - Fixed
LOCAL_FSstage downloads writing to the wrong path by using the destination file’s base name, consistent with cloud stages. - Fixed the
OAUTH_AUTHORIZATION_CODEcold-connect lockout caused by a cached invalid refresh token. The bad token is now evicted and the full browser flow restarts.
Version 2.4.3 (May 26, 2026)¶
New features and updates¶
- Bumped
@aws-sdk/*dependencies to version 3.1051.0 to addressfast-xml-buildersecurity vulnerabilities.
Bug fixes¶
- Fixed the platform-detection probe not aborting within 200 ms on Bun.
Version 2.4.2 (May 19, 2026)¶
Bug fixes¶
- Destroyed S3 clients after use in
s3_util.js(getFileHeader,uploadFileStream,nativeDownloadFile) to prevent keep-alive socket accumulation and memory leaks on long-lived pods. - Fixed
deserializeConnection()not derivingaccessUrlorhostfromaccount, which caused it to fail with a missingaccessUrlerror when onlyaccountwas provided. - Fixed the
OAUTH_AUTHORIZATION_CODEbrowser-popup loop caused by reauthentication opening a new browser window on every failed server response. This bug was a regression introduced in 2.4.1.
Version 2.4.1 (May 12, 2026)¶
New features and updates¶
- Reduced peak memory usage when streaming large result sets by reordering the chunk lifecycle to free the previous chunk before parsing the next one.
- Bumped axios to version 1.15.1 to address the deprecated
url.parse()warning in Node.js 22+ and a set of security issues, including CVE-2025-62718. - Pinned all
@aws-sdk/*dependencies to their latest minor (patch floats only) to avoid breaking changes for supported Node.js versions (Node 18+). - Removed the
browser-requestdependency and related dead code. - Dropped the
uuiddependency in favor of the Node.js built-incrypto.randomUUID().
Bug fixes¶
- Fixed file name pattern matching to not match dot-prefixed files or directories by default, aligning with standard glob behavior and the
dot: falsedefault. This bug was introduced in v2.3.3. - Fixed the
OAUTH_AUTHORIZATION_CODEcache not evicting entries on server390303errors.
Version 2.4.0 (Apr 7, 2026)¶
New features and updates¶
- Added the
browserRedirectPortconnection option to customize the port of the local server that receives the EXTERNALBROWSER authentication callback. - Bumped
@aws-sdk/*dependencies to address afast-xml-parservulnerability. - Improved keep-alive HTTP agents with a 30-second idle socket timeout that proactively discards stale connections before the server closes them, preventing socket hang up and ECONNRESET errors.
Bug fixes¶
- Fixed connection pools re-prompting browser authentication for every pooled connection when using EXTERNALBROWSER or OAUTH_AUTHORIZATION_CODE authenticators. The first connection now completes auth and caches tokens before subsequent pool connections start.
- Fixed session token renewal failing due to a malformed request, which caused long-running connections to disconnect instead of refreshing their expired session token.
- Fixed query context cache not being updated on failed queries, which could cause a stale cache when subsequent queries land on a different GS node.
Version 2.3.6 (Mar 25, 2026)¶
New features and updates¶
- Added support for every authenticator type (including external browser and Okta) in
connect(), matchingconnectAsync(). - Removed the
@google-cloud/storagedependency. GCS transfers now use the JSON API directly. TheforceGCPUseDownscopedCredentialconnection option has been removed as it is no longer needed. - Updated the default
jsonColumnVariantParserto fall back to eval-based parsing for non-JSON-compliant variant values (such asundefined,NaN, andInfinity), restoring pre-2.3.5 behavior while keepingJSON.parseas the primary parser.
Bug fixes¶
- Fixed the
OAUTH_AUTHORIZATION_CODEauthenticator not honoring theopenExternalBrowserCallbackconnection option. - Fixed
createConnection()andcreatePool()types to accept no arguments, matching the runtime behavior of loading configuration fromconnections.toml. - Fixed the
accountfield in theConnectionOptionstype to be optional, since it can be derived fromaccessUrlorhost. - Fixed external browser SSO authentication crashing when the SSO URL request returns a server-side error.
Version 2.3.5 (Mar 17, 2026)¶
New features and updates¶
- Added the ability to skip token file permission checks by using the
SF_SKIP_TOKEN_FILE_PERMISSIONS_VERIFICATIONenvironment variable. - Added Node 18+ to engines, which is the minimum officially supported version since the 2.x release.
- Added the
PLATFORMfield tologin-requesttelemetry. - Added request retries to previously uncovered query execution paths.
- Added the
rowStreamHighWaterMarkconnection option to control how many rows are buffered when streaming query results throughstatement.streamRows(). - Added a warning when converting query results to JavaScript numbers with precision loss.
- Added snake_case key support when loading
connections.tomlthroughcreateConnection()with no arguments. - Exported the
normalizeConnectionOptions()utility to convert snake_case connection keys to camelCase, with key aliases and acronym overrides. - Added the
LIBC_FAMILYandLIBC_VERSIONfields tologin-requesttelemetry. - Added the
crlDownloadMaxSizeconfiguration option to enforce a maximum response size limit when downloading CRL files. - Added RSASSA-PSS signature verification support for CRL validation.
- Improved error details when OAuth fails.
- Changed the default
jsonColumnVariantParsertoJSON.parse. - Updated Linux GNU minicore binaries to target glibc 2.18 for broader compatibility with older Linux distributions.
Bug fixes¶
-
Fixed OAuth crashing when using bundlers.
-
Fixed
Bindstyping to allow readonly arrays. -
Fixed the
connectAsync()method resolving before the connection is completed. -
Fixed incorrect handling of a callback argument that should be optional in
connect()andconnectAsync(). -
Fixed a bug where an invalid JWT was generated if a user accidentally set both the account and the host in the configuration.
-
Fixed a bug where parsing the JSON media type failed when it included an optional parameter from Microsoft Identity Platform v2.0 tokens, causing the OAuth Client Credentials flow to fail.
-
Fixed
disableSamlUrlChecktyping to use the correct casing:disableSamlURLCheck. -
Fixed
getDefaultCacheDir()crashing in environments where no user home directory is configured by falling back toos.tmpdir(). -
Fixed
SF_OCSP_RESPONSE_CACHE_DIRnot being used directly as the OCSP cache directory. -
Fixed bugs in
noProxyandNO_PROXYhandling:- The
.domain.comwildcard format was not correctly matching the destination host. .was incorrectly matching as any character instead of a literal dot.- Partial strings were incorrectly matching instead of requiring a full destination match.
- The
-
Fixed CRL ADVISORY mode to log failures at the warn level instead of debug.
-
Fixed OAuth Authorization Code reauthentication not using the refreshed access token when the cached access token is expired.
-
Fixed OAuth Authorization Code refresh token being removed from cache when the IdP does not return a new one.
-
Fixed an unhandled promise rejection when the server returns malformed query responses.
Version 2.3.4 (Feb 9, 2026)¶
New features and updates¶
- Reduced memory usage during PUT operations.
- Added
APPLICATION_PATHtologin-requesttelemetry. - Added Linux distribution details parsed from
/etc/os-releasetologin-requesttelemetry. - Bumped axios to version 1.13.4 to address a bug in axios interceptors.
- Bumped other dependencies to their latest minor versions.
Bug fixes¶
- Fixed inconsistent retry behavior across HTTP requests and ensured all recoverable failures are properly retried.
- Fixed invalid OAuth scope when
roleandoauthScopeare missing from the connection configuration. - Fixed
APPLICATIONfield not being passed from the connection configuration tologin-requesttelemetry. - Fixed build errors in bundlers caused by the
minicoremodule.