How to Connect to Snowflake from Node.js
Snowflake has one official Node.js driver, snowflake-sdk, written in pure JavaScript and maintained by Snowflake. There is no serious third-party alternative for server-side Node, so the package choice is settled. Current version is 2.4.3 (as of June 2026). What trips people up is not the driver but two things around it: the account identifier format and the shift away from password authentication.
npm install snowflake-sdkAuthentication: key-pair, not password
Starting in 2025, Snowflake blocks single-factor password authentication for programmatic connections by default. A username and password alone will be rejected on new accounts and on existing ones as the policy rolls out. The supported path for service connections is key-pair authentication, and it is worth setting up from the start rather than discovering it when a password stops working.
Generate an encrypted private key and a public key:
openssl genrsa 2048 | openssl pkcs8 -topk8 -v2 aes-256-cbc -inform PEM -out rsa_key.p8
openssl rsa -in rsa_key.p8 -pubout -out rsa_key.pubRegister the public key on the Snowflake user (strip the header, footer, and newlines from rsa_key.pub first):
ALTER USER my_service_user SET RSA_PUBLIC_KEY='MIIBIjANBgkq...';Then connect with the private key. The driver reads the PEM file, so you point it at the path and supply the passphrase:
import snowflake from "snowflake-sdk";
import fs from "node:fs";
const connection = snowflake.createConnection({
account: "myorg-myaccount",
username: "MY_SERVICE_USER",
authenticator: "SNOWFLAKE_JWT",
privateKeyPath: "/path/to/rsa_key.p8",
privateKeyPass: process.env.SNOWFLAKE_KEY_PASSPHRASE,
warehouse: "COMPUTE_WH",
database: "ANALYTICS",
schema: "PUBLIC",
});Keep the private key and its passphrase out of git. Password authentication still works in the examples below for local experimentation against older accounts (password: "..." instead of the key options), but do not build production connections on it.
The account identifier
The account option is the most common reason a connection fails before it does anything useful. The recommended format is the organization-account form: myorg-myaccount (your organization name, a hyphen, your account name). You can find both in Snowsight under your account details.
Older account-locator forms also exist (for example xy12345.eu-central-1), and which one you need depends on the account's age and region. If DNS resolution fails or you get Could not connect to Snowflake backend, the identifier format is the first thing to check, not the network.
Connecting and querying
The driver's classic API is callback-based. connect() takes a callback, and execute() takes a complete callback that receives the rows:
connection.connect((err, conn) => {
if (err) {
console.error("Unable to connect:", err.message);
return;
}
conn.execute({
sqlText: "SELECT C_NAME, C_ACCTBAL FROM CUSTOMER ORDER BY C_ACCTBAL DESC LIMIT 10",
complete: (err, stmt, rows) => {
if (err) {
console.error("Query failed:", err.message);
return;
}
for (const row of rows) {
console.log(row.C_NAME, row.C_ACCTBAL);
}
},
});
});Note that unquoted Snowflake identifiers are uppercase, so result columns come back uppercase (row.C_NAME) unless you quoted them in the table definition.
Promises with connectAsync
For modern async/await code, use connectAsync(), which returns a promise. execute() itself stays callback-based, so a small wrapper makes it awaitable:
await connection.connectAsync();
function query(sqlText, binds = []) {
return new Promise((resolve, reject) => {
connection.execute({
sqlText,
binds,
complete: (err, stmt, rows) => (err ? reject(err) : resolve(rows)),
});
});
}
const rows = await query("SELECT CURRENT_VERSION() AS V");
console.log(rows[0].V);Parameter binds
Never concatenate user input into SQL. The driver uses positional ? placeholders and a binds array:
connection.execute({
sqlText: "SELECT * FROM ORDERS WHERE STATUS = ? AND O_TOTALPRICE > ?",
binds: ["OPEN", 50000],
complete: (err, stmt, rows) => {
/* ... */
},
});Bind values are limited to strings, numbers, booleans, and null. For arrays of rows in a bulk insert, pass an array of arrays and the driver expands them.
You need a warehouse
Snowflake separates compute (warehouses) from storage. A query cannot run without an active warehouse, and "active" means either named in the connection options or set as the user's default. The error No active warehouse selected in the current session means neither was set. Add warehouse: "COMPUTE_WH" to the connection options or run USE WAREHOUSE COMPUTE_WH as your first statement.
Connection lifecycle
Snowflake connections are session-oriented, not a high-frequency pool like Postgres. Reuse one connection across requests rather than opening one per query. The driver offers a built-in connection pool via snowflake.createPool() for concurrent workloads, but many applications run fine with a single long-lived connection plus clientSessionKeepAlive: true for jobs that hold a session open for hours. Close cleanly when shutting down:
connection.destroy((err) => {
if (err) console.error("Error closing:", err.message);
});Error reference
| Error | Cause | Fix |
|---|---|---|
Could not connect to Snowflake backend / DNS failure | Wrong account identifier format | Use the myorg-myaccount form from Snowsight |
JWT token is invalid | Public key on the user does not match the private key, or wrong user | Re-register the public key; confirm the username |
Password was not specified / auth rejected | Single-factor password blocked | Switch to key-pair authentication |
No active warehouse selected in the current session | No warehouse in options or user default | Set warehouse or run USE WAREHOUSE |
Authentication token has expired mid-job | Long-running session timed out | Set clientSessionKeepAlive: true |
Verifying your data
After connecting, you usually want to browse what is in the warehouse. Snowsight works; a desktop client is faster for jumping between databases and schemas. We compared the options in Best Snowflake GUI Clients. For loading data, see Import CSV to Snowflake and Import JSON to Snowflake.
Mako connects to Snowflake (and 8 other databases) with AI-powered autocomplete. Try it free at mako.ai.
Skip the terminal. Use Mako.
Connect your database, write queries with AI assistance, and import/export data in clicks. Free to start.