Package Exports
- @stacksjs/env
- @stacksjs/env/cli.d.ts
- @stacksjs/env/crypto.d.ts
- @stacksjs/env/index.d.ts
- @stacksjs/env/index.js
- @stacksjs/env/parser.d.ts
- @stacksjs/env/plugin.d.ts
- @stacksjs/env/types.d.ts
- @stacksjs/env/utils.d.ts
Readme
@stacksjs/env
A secure .env file management package with built-in encryption support for Bun and Node.js.
Features
- 🔐 Automatic Encryption/Decryption - Secure your environment variables with public-key cryptography
- 🚀 Bun Plugin - Seamless integration with Bun's runtime
- 🔑 secp256k1 ECIES - Industry-standard elliptic curve encryption
- 📝 Variable Expansion - Support for
${VAR}, defaults, and alternates - 🔧 Command Substitution - Execute commands with
$(command) - 🎯 Multi-Environment - Manage multiple .env files for different environments
- 🛠️ CLI Tools - Full-featured CLI via buddy commands
- 🌍 Environment Detection - Native runtime, platform, and CI/CD detection utilities
Installation
bun add @stacksjs/envQuick Start
1. Auto-load .env files
import { autoLoadEnv } from '@stacksjs/env'
// Automatically loads .env files based on NODE_ENV or DOTENV_ENV
autoLoadEnv()
// Now use your environment variables
console.log(process.env.MY_SECRET)2. Programmatic Usage
import { loadEnv } from '@stacksjs/env'
// Load specific .env files
loadEnv({
path: ['.env.local', '.env'],
overload: false,
})3. Bun Plugin
Add to your bunfig.toml:
preload = ["./storage/framework/core/env/plugin.ts"]Or import in your preloader:
import '@stacksjs/env/plugin'Encryption
Encrypting .env Files
Use the buddy CLI to encrypt your environment variables:
# Encrypt .env file
buddy env:encrypt
# Encrypt specific file
buddy env:encrypt --file .env.production
# Encrypt specific keys only
buddy env:encrypt -k "SECRET**"
# Exclude specific keys from encryption
buddy env:encrypt -ek "PUBLIC**"This will:
- Generate a public/private keypair
- Store keys in
.env.keys(keep this secure!) - Encrypt values in your .env file
- Add
DOTENV_PUBLIC_KEYto your .env file
Decrypting .env Files
# Decrypt .env file
buddy env:decrypt
# Decrypt specific file
buddy env:decrypt --file .env.productionHow Encryption Works
The encryption uses secp256k1 ECIES (Elliptic Curve Integrated Encryption Scheme):
- A keypair is generated using secp256k1 (same as Bitcoin)
- Each value is encrypted with AES-256-GCM using an ephemeral key
- The ephemeral key is encrypted with the public key
- Only the private key can decrypt the values
Example encrypted .env:
# /-------------------[DOTENV_PUBLIC_KEY]--------------------/
# / public-key encryption for .env files /
# / [how it works](https://stacksjs.com/encryption) /
# /----------------------------------------------------------/
DOTENV_PUBLIC_KEY="034af93e93708b994c10f236c96ef88e47291066946cce2e8d98c9e02c741ced45"
# .env
API_KEY="encrypted:BDqDBibm4wsYqMpCjTQ6BsDHmMadg9K3dAt+Z9HPMfLEIRVz50hmLXPXRuDBXaJi..."
DB_PASSWORD="encrypted:AKx8Bh3m5xtZrNqDkUP7CuEInOcfg9L4eBy/2qt59vbSU0aN9WSmN..."CLI Commands
All commands are available through the buddy CLI:
Get Environment Variables
# Get a specific variable
buddy env:get API_KEY
# Get all variables as JSON
buddy env:get --all
# Get all variables in shell format
buddy env:get --all --format shell
# Pretty print JSON
buddy env:get --all --prettySet Environment Variables
# Set a variable (encrypted by default)
buddy env:set API_KEY "my-secret-value"
# Set without encryption
buddy env:set PUBLIC_URL "https://example.com" --plain
# Set in specific file
buddy env:set API_KEY "value" --file .env.productionManage Keypairs
# View keypair
buddy env:keypair
# View keypair for specific environment
buddy env:keypair --file .env.production
# Get specific key
buddy env:keypair DOTENV_PRIVATE_KEY
# Output in shell format
buddy env:keypair --format shellRotate Keys
# Rotate keypair and re-encrypt all values
buddy env:rotate
# Rotate for specific environment
buddy env:rotate --file .env.productionVariable Expansion
The env parser supports advanced variable expansion:
Basic Expansion
USERNAME="john"
DATABASE_URL="postgres://${USERNAME}@localhost/mydb"
# Result: postgres://john@localhost/mydbDefault Values
# Use default if unset or empty
DATABASE_HOST=${DB_HOST:-localhost}
DATABASE_PORT=${DB_PORT:-5432}
# Use default only if unset (empty is ok)
API_URL=${API_BASE_URL-https://api.example.com}Alternate Values
NODE_ENV=production
# Use alternate if set and non-empty
DEBUG_MODE=${NODE_ENV:+false}
LOG_LEVEL=${NODE_ENV:+error}
# Use alternate if set (empty is ok)
CACHE_ENABLED=${NODE_ENV+true}Command Substitution
# Execute command and use output
CURRENT_USER=$(whoami)
BUILD_TIME=$(date +%s)
GIT_COMMIT=$(git rev-parse HEAD)Environment Detection
The package includes native utilities to detect runtime, platform, and CI/CD environments:
import {
// Runtime detection
isBun,
isNode,
runtime,
runtimeInfo,
// Platform detection
platform,
isWindows,
isMacOS,
isLinux,
// Environment detection
hasTTY,
hasWindow,
isCI,
isDebug,
isMinimal,
isColorSupported,
// Provider detection
provider,
providerInfo,
} from '@stacksjs/env'
// Check runtime
console.log(runtime) // 'bun' | 'node' | 'unknown'
console.log(runtimeInfo) // { name: 'bun', version: '1.3.2' }
// Check platform
console.log(platform) // 'darwin' | 'linux' | 'win32' | etc.
console.log(isMacOS) // true/false
// Check CI environment
console.log(isCI) // true/false
console.log(provider) // 'github' | 'gitlab' | 'vercel' | etc.
console.log(providerInfo) // { name: 'GitHub Actions', detected: true }Supported CI/CD Providers
- GitHub Actions
- GitLab CI
- CircleCI
- Travis CI
- Jenkins
- Vercel
- Netlify
- Heroku
- AWS
- Azure
- Cloudflare Pages
- Railway
- Render
Multi-Environment Support
Load different .env files based on environment:
# .env.local (highest priority)
# .env.development
# .env.production
# .env (lowest priority)The loader will automatically detect NODE_ENV or DOTENV_ENV and load the appropriate files.
Environment-Specific Keys
Keys are automatically namespaced by environment:
# .env.keys
DOTENV_PUBLIC_KEY="..."
DOTENV_PRIVATE_KEY="..."
DOTENV_PUBLIC_KEY_PRODUCTION="..."
DOTENV_PRIVATE_KEY_PRODUCTION="..."
DOTENV_PUBLIC_KEY_CI="..."
DOTENV_PRIVATE_KEY_CI="..."Security Best Practices
- Never commit
.env.keys- Add to.gitignore - Commit encrypted
.envfiles - They're safe to commit - Store private keys securely - Use your CI/CD secrets manager
- Rotate keys regularly - Use
buddy env:rotate - Use environment-specific keys - Different keys for dev/staging/prod
API Reference
autoLoadEnv(options?)
Automatically load .env files based on environment.
import { autoLoadEnv } from '@stacksjs/env'
autoLoadEnv({
env: 'production', // Override environment detection
overload: false, // Don't override existing vars
quiet: true, // Suppress output
cwd: '/path/to/project'
})loadEnv(options)
Load specific .env files.
import { loadEnv } from '@stacksjs/env'
loadEnv({
path: ['.env.local', '.env'],
overload: false,
privateKey: 'your-private-key',
keysFile: '.env.keys',
quiet: false
})encryptEnv(options)
Encrypt a .env file.
import { encryptEnv } from '@stacksjs/env'
const result = encryptEnv({
file: '.env',
keysFile: '.env.keys',
key: 'SECRET**', // Only encrypt keys matching pattern
excludeKey: 'PUBLIC**', // Exclude keys matching pattern
stdout: false
})decryptEnv(options)
Decrypt a .env file.
import { decryptEnv } from '@stacksjs/env'
const result = decryptEnv({
file: '.env',
keysFile: '.env.keys',
stdout: false
})setEnv(key, value, options)
Set an environment variable.
import { setEnv } from '@stacksjs/env'
setEnv('API_KEY', 'my-secret', {
file: '.env',
keysFile: '.env.keys',
plain: false // Encrypt by default
})getEnv(key?, options)
Get environment variable(s).
import { getEnv } from '@stacksjs/env'
// Get single value
const result = getEnv('API_KEY', {
file: '.env',
keysFile: '.env.keys'
})
// Get all values
const result = getEnv(undefined, {
all: true,
format: 'json', // or 'shell' or 'eval'
prettyPrint: true
})Migration from dotenvx
This package replaces @dotenvx/dotenvx and bun-plugin-dotenvx with a native Bun implementation.
Breaking Changes
None! The API is designed to be compatible with dotenvx.
Migration Steps
- Update your
bunfig.tomlpreload - Update imports from
@dotenvx/dotenvxto@stacksjs/env - buddy commands remain the same
📈 Changelog
Please see our releases page for more information on what has changed recently.
🚜 Contributing
Please review the Contributing Guide for details.
🏝 Community
For help, discussion about best practices, or any other conversation that would benefit from being searchable:
For casual chit-chat with others using this package:
Join the Stacks Discord Server
📄 License
The MIT License (MIT). Please see LICENSE for more information.
Made with 💙