CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-dotenv

Loads environment variables from .env file into process.env with support for encrypted .env.vault files

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

vault-decryption.mddocs/

Vault Decryption

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.

Capabilities

Decrypt Function

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);
}

Vault Workflow

Automatic Vault Loading

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));

Environment-Specific Keys

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 });

Multi-Key Support

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 });

Vault File Format

.env.vault Structure

The .env.vault file contains encrypted environment data:

DOTENV_VAULT_DEVELOPMENT="A5q7B2C8D9E0F1G2H3I4J5K6L7M8..."
DOTENV_VAULT_PRODUCTION="X9Y0Z1A2B3C4D5E6F7G8H9I0J1K2..."
DOTENV_VAULT_STAGING="P3Q4R5S6T7U8V9W0X1Y2Z3A4B5C6..."

Key Format

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)
└── Scheme

Error Handling

Common 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);
  }
}

Key Validation

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);
}

Advanced Vault Usage

Custom Vault Processing

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);
}

Vault Creation Helpers

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');

Security Considerations

Key Management

  • Store DOTENV_KEY securely in your deployment environment
  • Never commit DOTENV_KEY to version control
  • Rotate keys regularly using multi-key support
  • Use different keys for different environments

Vault File Security

  • .env.vault files can be safely committed to version control
  • Encrypted data is secured with AES-256-GCM
  • Each environment uses separate encryption keys
  • Vault files cannot be decrypted without the corresponding DOTENV_KEY

Install with Tessl CLI

npx tessl i tessl/npm-dotenv

docs

environment-loading.md

environment-population.md

file-parsing.md

index.md

vault-decryption.md

tile.json