Support for encrypted .env.vault files using AES-256-GCM encryption for secure deployments. Enables storing sensitive environment variables in encrypted form while maintaining the same simple dotenv workflow.
Decrypts encrypted environment variable ciphertext using AES-256-GCM encryption.
/**
* Decrypt ciphertext using AES-256-GCM
* @param encrypted - The encrypted ciphertext string (base64 encoded)
* @param keyStr - The decryption key string (at least 64 characters)
* @returns Decrypted plaintext string
*/
function decrypt(encrypted: string, keyStr: string): string;Usage Examples:
const dotenv = require('dotenv');
// Direct decryption (rarely used directly)
const encrypted = 'A5q7B2C8D9E0F1G2H3I4J5K6L7M8N9O0P1Q2R3S4T5U6V7W8X9Y0Z1A2B3C4D5E6F7G8H9I0J1K2L3M4N5O6P7Q8R9S0T1U2V3W4X5Y6Z7A8B9C0D1E2F3G4H5I6J7K8L9M0N1O2P3Q4R5S6T7U8V9W0X1Y2Z3A4B5C6D7E8F9G0H1I2J3K4L5M6N7O8P9Q0R1S2T3U4V5W6X7Y8Z9A0B1C2D3E4F5G6H7I8J9K0L1M2N3O4P5Q6R7S8T9U0V1W2X3Y4Z5A6B7C8D9E0F1G2H3I4J5K6L7M8N9O0P1Q2R3S4T5U6V7W8X9Y0Z1A2B3C4D5E6F7G8H9I0J1K2L3M4N5O6P7Q8R9S0T1U2V3W4X5Y6Z7A8B9C0D1E2F3G4H5I6J7K8L9M0N1O2P3Q4R5S6T7U8V9W0X1Y2Z3A4B5C6D7E8F9G0H1I2J3K4L5M6N7O8P9Q0R1S2T3U4V5W6X7Y8Z9A0B1C2D3E4F5G6H7I8J9K0L1M2N3O4P5Q6R7S8T9U0V1W2X3Y4Z5A6B7C8D9E0F1G2H3I4J5K6L7M8N9O0P1Q2R3S4T5U6V7W8X9Y0Z1A2B3C4D5E6F7G8H9I0J1K2L3M4N5O6P7Q8R9S0T1U2V3W4X5Y6Z7A8B9C0D1E2F3G4H5I6J7K8L9M0N1O2P3Q4R5S6T7U8V9W0X1Y2Z3A4B5C6D7E8F9G0H1I2J3K4L5M6N7O8P9Q0R1S2T3U4V5W6X7Y8Z9A0B1C2D3E4F5G6H7I8J9K0L1M2N3O4P5Q6R7S8T9U0V1W2X3Y4Z5A6B7C8D9E0F1G2H3I4J5K6L7M8N9O0P1Q2R3S4T5U6V7W8X9Y0Z1A2B3C4D5E6F7G8H9I0J1K2L3M4N5O6P7Q8R9S0T1U2V3W4X5Y6Z7A8B9C0D1E2F3G4H5I6J7K8L9M0N1O2P3Q4R5S6T7U8V9W0X1Y2Z3A4B5C6D7E8F9G0H1I2J3K4L5M6N7O8P9Q0R1S2T3U4V5W6X7Y8Z9A0B1C2D3E4F5G6H7I8J9K0L1M2';
const key = 'dotenv://:key_1234567890abcdef1234567890abcdef1234567890abcdef12@dotenvx.com/vault/.env.vault?environment=production';
try {
const decrypted = dotenv.decrypt(encrypted, key);
console.log('Decrypted content:', decrypted);
// Output: "DATABASE_URL=postgres://prod-server/db\nAPI_KEY=prod-secret-key"
} catch (error) {
console.error('Decryption failed:', error.message);
}The config() function automatically handles .env.vault files when DOTENV_KEY is present:
const dotenv = require('dotenv');
// Set DOTENV_KEY environment variable
process.env.DOTENV_KEY = 'dotenv://:key_1234567890abcdef@dotenvx.com/vault/.env.vault?environment=production';
// config() automatically detects and decrypts .env.vault
const result = dotenv.config();
console.log('Loaded from vault:', Object.keys(result.parsed));DOTENV_KEY URLs specify which environment to decrypt:
// Development environment
const devKey = 'dotenv://:key_dev123@dotenvx.com/vault/.env.vault?environment=development';
// Production environment
const prodKey = 'dotenv://:key_prod456@dotenvx.com/vault/.env.vault?environment=production';
// Staging environment
const stagingKey = 'dotenv://:key_stage789@dotenvx.com/vault/.env.vault?environment=staging';
// Load specific environment
dotenv.config({ DOTENV_KEY: prodKey });Support for comma-separated keys for key rotation:
const dotenv = require('dotenv');
// Multiple keys for rotation support
const multiKey = 'dotenv://:key_old123@dotenvx.com/vault/.env.vault?environment=prod,dotenv://:key_new456@dotenvx.com/vault/.env.vault?environment=prod';
// Will try each key until successful
dotenv.config({ DOTENV_KEY: multiKey });The .env.vault file contains encrypted environment data:
DOTENV_VAULT_DEVELOPMENT="A5q7B2C8D9E0F1G2H3I4J5K6L7M8..."
DOTENV_VAULT_PRODUCTION="X9Y0Z1A2B3C4D5E6F7G8H9I0J1K2..."
DOTENV_VAULT_STAGING="P3Q4R5S6T7U8V9W0X1Y2Z3A4B5C6..."DOTENV_KEY uses URI format with specific components:
dotenv://:key_1234567890abcdef@dotenvx.com/vault/.env.vault?environment=production
│ │ │ │ │ │
│ │ │ │ │ └── Environment name
│ │ │ │ └── Vault file path
│ │ │ └── Host (ignored in decryption)
│ │ └── Decryption key (last 64 characters used)
│ └── Password field (contains the key)
└── SchemeCommon vault-related errors and their handling:
const dotenv = require('dotenv');
try {
const result = dotenv.config({ DOTENV_KEY: 'invalid-key' });
if (result.error) {
handleVaultError(result.error);
}
} catch (error) {
handleVaultError(error);
}
function handleVaultError(error) {
switch (error.code) {
case 'INVALID_DOTENV_KEY':
console.error('Invalid DOTENV_KEY format. Must be valid URI format.');
console.error('Expected: dotenv://:key_xxx@host/vault/.env.vault?environment=env');
break;
case 'NOT_FOUND_DOTENV_ENVIRONMENT':
console.error('Environment not found in .env.vault file.');
console.error('Available environments might be: development, production, staging');
break;
case 'DECRYPTION_FAILED':
console.error('Failed to decrypt .env.vault. Check your DOTENV_KEY.');
break;
case 'MISSING_DATA':
console.error('Cannot parse .env.vault file - file may be corrupted.');
break;
default:
console.error('Vault error:', error.message);
}
}Validate DOTENV_KEY format before use:
function validateDotenvKey(key) {
if (!key || typeof key !== 'string') {
throw new Error('DOTENV_KEY must be a string');
}
try {
const url = new URL(key);
if (url.protocol !== 'dotenv:') {
throw new Error('DOTENV_KEY must use dotenv:// protocol');
}
if (!url.password || url.password.length < 64) {
throw new Error('DOTENV_KEY must contain at least 64-character key');
}
const environment = url.searchParams.get('environment');
if (!environment) {
throw new Error('DOTENV_KEY must specify environment parameter');
}
return {
key: url.password,
environment: environment,
valid: true
};
} catch (error) {
throw new Error(`Invalid DOTENV_KEY format: ${error.message}`);
}
}
// Usage
try {
const keyInfo = validateDotenvKey(process.env.DOTENV_KEY);
console.log(`Valid key for environment: ${keyInfo.environment}`);
} catch (error) {
console.error(error.message);
}Manual vault file processing for advanced workflows:
const dotenv = require('dotenv');
const fs = require('fs');
function processVaultManually(vaultPath, dotenvKey) {
// Parse vault file
const vaultContent = fs.readFileSync(vaultPath, 'utf8');
const vaultData = dotenv.parse(vaultContent);
// Extract key information
const url = new URL(dotenvKey);
const key = url.password;
const environment = url.searchParams.get('environment').toUpperCase();
// Get encrypted data for environment
const envKey = `DOTENV_VAULT_${environment}`;
const encrypted = vaultData[envKey];
if (!encrypted) {
throw new Error(`Environment ${environment} not found in vault`);
}
// Decrypt and parse
const decrypted = dotenv.decrypt(encrypted, key);
return dotenv.parse(decrypted);
}
// Usage
try {
const config = processVaultManually('.env.vault', process.env.DOTENV_KEY);
console.log('Manually processed vault:', Object.keys(config));
} catch (error) {
console.error('Manual vault processing failed:', error.message);
}Utilities for working with vault data (informational - creation requires external tools):
// Note: Actual vault creation requires dotenvx CLI tool
// This is for understanding the data structure
function analyzeVaultFile(vaultPath) {
const fs = require('fs');
const dotenv = require('dotenv');
const content = fs.readFileSync(vaultPath, 'utf8');
const vaultData = dotenv.parse(content);
const environments = Object.keys(vaultData)
.filter(key => key.startsWith('DOTENV_VAULT_'))
.map(key => key.replace('DOTENV_VAULT_', '').toLowerCase());
return {
environments,
totalSize: content.length,
encryptedCount: environments.length
};
}
// Usage
const vaultInfo = analyzeVaultFile('.env.vault');
console.log('Available environments:', vaultInfo.environments);
console.log('Vault file size:', vaultInfo.totalSize, 'bytes');