Node.js SDK

Load secrets directly into a Node.js application at startup.

Node.js SDK

Load secrets directly into your Node.js application at startup. Async-first API with one-liner facade or fluent builder for full control.

Install

npm install @envilder/sdk

Quick start: one-liner

Load secrets from a map file and inject them into process.env:

import { Envilder } from '@envilder/sdk';

// Resolve secrets and inject into process.env
await Envilder.load('envilder.json');

const dbPassword = process.env.DB_PASSWORD;

Resolve without injecting

Get secrets as a Map without modifying the environment:

import { Envilder } from '@envilder/sdk';

const secrets = await Envilder.resolveFile('envilder.json');
const dbPassword = secrets.get('DB_PASSWORD');

Fluent builder with overrides

Override provider settings programmatically using the fluent API:

import { Envilder, SecretProviderType } from '@envilder/sdk';

const secrets = await Envilder.fromMapFile('envilder.json')
  .withProvider(SecretProviderType.Azure)
  .withVaultUrl('https://my-vault.vault.azure.net')
  .resolve();

// Or inject directly
await Envilder.fromMapFile('envilder.json')
  .withProfile('staging')
  .inject();

Environment-based loading

Recommended for multi-environment apps. Map each environment to its own secrets file:

import { Envilder } from '@envilder/sdk';

const env = process.env.APP_ENV ?? 'development';

await Envilder.load(env, {
  production: 'prod-secrets.json',
  development: 'dev-secrets.json',
  test: null,  // no secrets loaded
});

Secret validation

Opt-in validation ensures all resolved secrets have non-empty values:

import { Envilder, validateSecrets } from '@envilder/sdk';

const secrets = await Envilder.resolveFile('envilder.json');
validateSecrets(secrets); // throws SecretValidationError if any value is empty

Map file contract validation

Check, without loading anything and without using or printing any value, that the map file is valid and that every declared secret exists with the current credentials: the same check as envilder validate. Expected validation failures are returned in the result instead of thrown; a missing map file still throws. Each key reports exists, missing, access_denied, authentication_failed or provider_error:

See the envilder validate reference for the statuses and the permissions the check needs →

import { Envilder } from '@envilder/sdk';

const result = await Envilder.fromMapFile('envilder.json').validateContract();
if (!result.isValid) {
  for (const error of result.mapFileErrors) {
    console.log(`${error.key}: ${error.message}`);
  }
  for (const key of result.keys.filter((k) => k.status !== 'exists')) {
    console.log(`${key.variable} (${key.path}): ${key.status}`);
  }
}

To fail the load instead, enable contract validation on the builder. The check runs once before resolving and the error names the failing keys, never their values. It is off by default, so a normal load makes no extra provider call. Unlike secret validation, which checks resolved values, it checks the map file and the keys before resolving:

await Envilder.fromMapFile('envilder.json')
  .withContractValidation()
  .inject(); // throws ContractValidationError
💡
Runnable examples. A Vitest project with Testcontainers and an Aspire TypeScript AppHost resolve a map file against AWS SSM and Azure Key Vault (emulated with LocalStack and Lowkey Vault) and pass the values to containers, with no .env file: typescript-testcontainers · typescript-aspire

Full documentation →