First, generate or obtain your dotenvx private key. If you don't have one:
# Generate a new dotenvx key (if needed)
dotenvx encryptThis creates .env.keys in your project.
Pick the provider that matches your workflow:
# Password (default, works everywhere)
vhsm encrypt
# Windows DPAPI (machine/user bound)
vhsm encrypt -p dpapi
# FIDO2 (hardware-backed - Windows Hello, security keys, mobile)
vhsm encrypt -p fido2
# Custom paths still work with any provider
vhsm encrypt -p fido2 -fk .env.secure -o .env.vhsm- password prompts for an 8+ character passphrase.
- dpapi never prompts and ties secrets to your Windows account.
- fido2 launches a browser flow for FIDO2 authentication (Windows Hello, security keys, mobile - credential is reused for multiple keys).
All providers output VHSM_PRIVATE_KEY=<provider>:... lines to .env.keys.encrypted (mode 600). Delete .env.keys unless passing -nd.
Replace dotenvx run with vhsm run:
# Before (insecure - key in plaintext)
dotenvx run npm start
# After (secure - key encrypted, decrypted at runtime)
vhsm run -- npm start # Provider auto-detectedEnsure encrypted keys are never committed:
echo ".env.keys.encrypted" >> .gitignore
echo ".env.keys" >> .gitignore # Also ignore plaintext keysIf you need to restore the .env.keys file from the encrypted version:
vhsm decrypt --restore
# or with custom paths
vhsm decrypt -ef .env.vhsm -r -fk .env.securevhsm run -ef .secrets/dotenvx.key.encrypted -- npm startFor maximum security, disable session caching:
vhsm run --no-cache -- npm start
# or
vhsm run -nc -- npm startSet cache to expire after 30 minutes:
vhsm run --cache-timeout 1800000 -- npm start
# or
vhsm run -ct 1800000 -- npm startvhsm run -- npm test --coverage
vhsm run -- node server.js --port 3000
vhsm run -- python manage.py runserverUpdate your package.json:
{
"scripts": {
"start": "vhsm run -- node server.js",
"dev": "vhsm run -- nodemon server.js",
"test": "vhsm run -- jest"
}
}Then run:
npm start
npm run dev
npm testCreate .vhsmrc.json:
{
"provider": "password",
"cacheTimeout": 1800000,
"enableCache": true
}export VHSM_PROVIDER=password
export VHSM_CACHE_TIMEOUT=3600000
export VHSM_ENABLE_CACHE=true
vhsm run npm start# Use config file defaults
vhsm run npm start
# Override cache timeout for this command
vhsm run -ct 600000 -- npm start
# Disable cache for this command
vhsm run -nc npm start
# Use custom encrypted key file
vhsm run -ef custom/path/.env.keys.encrypted -- npm start-
Share encrypted key securely:
- Use a secure secret sharing service (1Password, Bitwarden, etc.)
- Or use encrypted communication channels
- Never commit to version control
-
Each developer encrypts with their own passphrase:
# Developer A vhsm encrypt -o .env.keys.encrypted # Developer B (with their own passphrase) vhsm encrypt -o .env.keys.encrypted
-
Or use a shared team passphrase (stored in password manager)
-
Restore keys for new team members:
# New team member receives encrypted key and passphrase vhsm decrypt -r -ef .env.keys.encrypted
For CI/CD, use environment variables or secret management:
# In CI, set decrypted key directly (from secure vault)
export DOTENV_PRIVATE_KEY="$(vault read -field=key secret/dotenvx)"
dotenvx run npm testvhsm is designed for local development. In CI/CD, use your platform's secret management.
Use different encrypted keys for different environments:
# Development
vhsm encrypt -fk .env.keys.dev -o .env.keys.dev.encrypted
# Staging
vhsm encrypt -fk .env.keys.staging -o .env.keys.staging.encrypted
# Production (use proper secret management, not vhsm)# Encrypt specific keys only
vhsm encrypt -k DATABASE_URL API_KEY
# Exclude specific keys from encryption
vhsm encrypt -ek DATABASE_URL
# Encrypt specific env files
vhsm encrypt -f .env.production .env.staging
# Decrypt specific keys
vhsm decrypt -k DATABASE_URL API_KEY
# Decrypt specific env files
vhsm decrypt -f .env.production# Check if file exists
ls -la .env.keys.encrypted
# Use custom path
vhsm run -ef /path/to/key.encrypted -- npm start# Clear cache and retry
vhsm clear-cache
vhsm run npm start# Install dotenvx globally
npm install -g @dotenvx/dotenvx
# Or use npx
vhsm run -- npm start # vhsm already includes dotenvx, no need to call it separately
# Better: vhsm includes dotenvx, no PATH needed# Dockerfile
FROM node:18
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
CMD ["vhsm", "run", "npm", "start"]Note: For Docker, consider implementing a docker-secrets provider instead.
.PHONY: start
start:
vhsm run npm start
.PHONY: test
test:
vhsm run -- npm test#!/bin/bash
# deploy.sh
vhsm run npm run build
vhsm run npm run deploy