Skip to content

Why node vault client

kurok edited this page Aug 31, 2026 · 1 revision

Why this client

There are several HashiCorp Vault clients for Node.js. This page explains what node-vault-client optimises for and how it differs from the alternatives on those points.

Scope, stated up front: this is not an exhaustive feature matrix. It compares the dimensions this client is built around — KV handling, token lifecycle, configuration integration and release hygiene. Other clients lead on other dimensions; pick the one whose strengths match your problem. All claims below were checked against each project's published source in August 2026 and are dated, because they will drift.

The clients compared

latest stars what it is
node-vault-client 2.1.2 24 Opinionated KV client with managed auth
node-vault 0.12.0 (2026-03) 555 The long-standing generic endpoint wrapper
@litehex/node-vault 1.1.7 (2026-08) 374 Modern TypeScript-native, schema-generated commands
hashi-vault-js 0.5.3 (2026-08) 43 Broad endpoint coverage, KV v2 focused
vault-api 1.1.2 (2023-10) 11 Axios-like wrapper; no commits since Oct 2023

Where this client differs

node-vault-client node-vault @litehex hashi-vault-js vault-api
Same code path for KV v1 and v2 yes you build the paths separate helpers v2 only yes
Mount version auto-detection yes, opt-in, cached no no no yes
Static mount→version map yes no no no no
Automatic token renewal yes, by default opt-in call no manual only no
Renewal survives >24.8 day TTLs yes
node-config integration yes no no no no
Namespace on every request yes, conformance-tested client-wide client-wide client-wide not supported
Runs on Node 18 yes yes needs ≥20 needs ≥20 unspecified

KV v1 and v2 without path surgery

This is the main reason the client exists. In Vault, a KV v2 read is GET secret/data/foo and its metadata lives at secret/metadata/foo, while v1 is just GET secret/foo. Most clients make that your problem:

// node-vault — you build v2 paths and unwrap the envelope yourself
await vault.read('secret/data/hello');            // .data.data.value
await vault.update('secret/data/hello', { data: { value: 'x' } });

// node-vault-client — same call regardless of mount version
const lease = await vault.read('secret/hello');
lease.getValue('value');

Two ways to tell it which mounts are v2: ask Vault once per mount (kv: { autoDetect: true }, cached in a bounded LRU), or declare them (engines: { secret: 2 }) with no detection request — which is what you need when your token may not read sys/internal/ui/mounts. None of the other four offers both, and only this client and the dormant vault-api offer detection at all.

hashi-vault-js is KV v2 only, with the data/metadata segments hard-coded, so a v1 mount is out of reach.

The token takes care of itself

Authenticate once at boot and stop thinking about it. Login happens lazily on first use, the token is renewed by a background timer, and concurrent callers share a single in-flight login rather than stampeding the auth endpoint on a cold start.

Renewal also survives long TTLs: setTimeout silently overflows past ~24.8 days, so a 30-day token would renew immediately and then never again. This client schedules through long-timeout to avoid that.

Of the alternatives, only node-vault renews automatically, and it is opt-in — you call startTokenRenewal() and manage it. @litehex/node-vault implements no auth backends at all (you supply a token you obtained elsewhere), and neither it nor vault-api has any renewal. hashi-vault-js exposes renewToken() for you to schedule yourself.

Secrets straight into node-config

If your app already uses node-config, one file maps config keys to Vault paths and one call fills them in — no glue code, no secrets in your config files:

// config/custom-vault-variables.js
module.exports = { db: { password: 'secret/orders/db#password' } };

await VaultClient.boot('main', { /* ... */ }).fillNodeConfig();
config.get('db.password');   // value from Vault

Each Vault path is fetched once regardless of how many keys reference it. No other client in this comparison integrates with node-config.

Namespaces that actually cover every request

Vault Enterprise namespaces are easy to get almost right: apply X-Vault-Namespace to your data calls and forget the login, token lookup or renewal. That was a real bug here once, and the fix came with a conformance suite that drives all four auth backends against a stubbed Vault and fails if any request from any backend is missing the header. It is the difference between "the option exists" and "it is covered by tests".

vault-api has no namespace support at all — the header appears nowhere in its source.

Release hygiene

  • Published to npm with provenance attestation, so the tarball is cryptographically linked to the workflow run and commit that built it.
  • Unit and docker-compose end-to-end suites run on Node 18, 20, 22 and 24 on every PR, against real Vault servers (one KV v1, one KV v2).
  • Enforced coverage thresholds, npm audit --audit-level=high, CodeQL, Snyk, and all GitHub Actions pinned to commit SHAs.

One data point on the alternatives' supply chains: vault-api depends on axios ^0.21.4, and because the caret range on a 0.x version resolves only within >=0.21.4 <0.22.0, it cannot pick up the patched axios releases — 23 advisories affect that version, 8 of them high severity. Combined with no commits since October 2023, it is hard to recommend for new work.

Choosing

  • You read and write KV secrets in an app and want to stop thinking about tokens, mount versions and lease plumbing → this client.
  • You use node-config → this client, for fillNodeConfig() alone.
  • You must run on Node 18 → this client or node-vault; the other two require Node 20+.
  • You need an endpoint this client does not wrap → it is still one call away via request(), which sends a literal path with auth and namespace headers already applied.

Comparison compiled August 2026 against node-vault 0.12.0, @litehex/node-vault 1.1.7, hashi-vault-js 0.5.3 and vault-api 1.1.2, by reading each project's published source, package metadata and CI configuration rather than its marketing. Star counts are from the GitHub API on 2026-08-31. If something here is out of date or wrong, please open an issue — we would rather fix it than leave it.