Securely load environment variables from AWS SSM Parameter Store or Azure Key Vault directly into your Node.js application. Zero vendor lock-in — secrets stay in your cloud.
Part of the Envilder project.
- Node.js 20+
- AWS provider: AWS credentials configured (CLI, environment variables, or IAM role)
- Azure provider: Azure credentials via
az login, managed identity, or environment variables
npm install @envilder/sdkimport { Envilder } from '@envilder/sdk';
// Resolve secrets and inject into process.env
await Envilder.load('secrets-map.json');
console.log('DB_PASSWORD loaded:', !!process.env.DB_PASSWORD);import { Envilder } from '@envilder/sdk';
const secrets = await Envilder.resolveFile('secrets-map.json');
console.log(secrets.get('DB_PASSWORD')); // avoid logging secrets in productionOverride the map file's $config at runtime — useful for switching providers,
profiles, or vault URLs per environment:
import { Envilder, SecretProviderType } from '@envilder/sdk';
// Override provider + vault URL
const secrets = await Envilder.fromMapFile('secrets-map.json')
.withProvider(SecretProviderType.Azure)
.withVaultUrl('https://my-vault.vault.azure.net')
.resolve();
// Override AWS profile and inject
await Envilder.fromMapFile('secrets-map.json')
.withProfile('staging')
.inject();Route secret loading based on your current environment. Each environment
maps to its own secrets file (or null to skip loading):
import { Envilder } from '@envilder/sdk';
const env = process.env.APP_ENV ?? 'development';
// Resolve + inject into process.env
await Envilder.load(env, {
production: 'prod-secrets.json',
development: 'dev-secrets.json',
test: null, // no secrets loaded
});Resolve without injecting:
const secrets = await Envilder.resolveFile(env, {
production: 'prod-secrets.json',
development: 'dev-secrets.json',
test: null,
});Behavior:
- If the environment maps to a file path, secrets are loaded from that file.
- If the environment maps to
nullor is not in the mapping, an emptyMapis returned silently. - Empty or whitespace-only environment names throw
Error.
Opt-in validation ensures all resolved secrets have non-empty values:
import { Envilder, validateSecrets } from '@envilder/sdk';
const secrets = await Envilder.resolveFile('secrets-map.json');
validateSecrets(secrets); // throws SecretValidationError if any value is emptyvalidateSecrets() checks that:
- The map is not empty (throws
SecretValidationErrorwith emptymissingKeys) - Every value is non-empty (throws
SecretValidationErrorlisting the failing keys) - Passes silently when all values are present
import { SecretValidationError, validateSecrets } from '@envilder/sdk';
try {
validateSecrets(secrets);
} catch (err) {
if (err instanceof SecretValidationError) {
console.log(`Missing: ${err.missingKeys.join(', ')}`);
}
}Implement the ISecretProvider interface to plug in a custom backend
(e.g., HashiCorp Vault, GCP Secret Manager):
import {
EnvilderClient,
MapFileParser,
type ISecretProvider,
} from '@envilder/sdk';
import { readFileSync } from 'node:fs';
class MyCustomProvider implements ISecretProvider {
async getSecrets(names: string[]): Promise<Map<string, string>> {
// fetch from your custom backend
return new Map();
}
}
const json = readFileSync('secrets-map.json', 'utf-8');
const mapFile = new MapFileParser().parse(json);
const provider = new MyCustomProvider();
const client = new EnvilderClient(provider);
const secrets = await client.resolveSecrets(mapFile);
EnvilderClient.injectIntoEnvironment(secrets);| Method | Description |
|---|---|
load(path) |
Resolve secrets and inject into process.env |
resolveFile(path) |
Resolve secrets, return as Map<string, string> |
load(env, mapping) |
Environment-based resolve + inject |
resolveFile(env, mapping) |
Environment-based resolve |
fromMapFile(path) |
Returns fluent builder for configuration |
| Method | Description |
|---|---|
withProvider(type) |
Override secret provider (AWS/Azure) |
withProfile(name) |
Override AWS named profile |
withVaultUrl(url) |
Override Azure Key Vault URL |
resolve() |
Resolve secrets, return as Map |
inject() |
Resolve + inject into process.env |
| Function | Description |
|---|---|
validateSecrets(map) |
Throws SecretValidationError if any value is empty or map is empty |
{
"$config": {
"provider": "aws",
"profile": "my-profile"
},
"DB_PASSWORD": "/app/prod/db-password",
"API_KEY": "/app/prod/api-key"
}Supported providers: aws (default), azure.
For Azure, add vaultUrl:
{
"$config": {
"provider": "azure",
"vaultUrl": "https://my-vault.vault.azure.net"
},
"DB_PASSWORD": "myapp-prod-db-password",
"API_KEY": "myapp-prod-api-key"
}See the root README for the full map file reference.