envkeeper
Version:
đĄī¸ The most human-friendly environment variable validator for Node.js - Beautiful error messages with actionable suggestions that actually help you fix issues
733 lines (557 loc) âĸ 19.3 kB
Markdown
# đĄī¸ EnvKeeper
[](https://badge.fury.io/js/envkeeper)
[](https://opensource.org/licenses/MIT)
[](https://nodejs.org)
**The most human-friendly environment variable validator for Node.js**
Stop struggling with cryptic environment variable errors! EnvKeeper provides beautiful, actionable error messages that actually help you fix issues. No more guessing what went wrong - get clear guidance on exactly what needs to be fixed.
## ⨠Why EnvKeeper is Different
### đ¨ Beautiful, Human-Friendly Error Messages
Unlike other validators that give you plain text errors, EnvKeeper provides:
- **Colorful, formatted output** that's easy to read
- **Actionable suggestions** that tell you exactly what to do
- **Smart examples** based on your variable names
- **Context-aware guidance** for common mistakes
### Example Error Output:
```
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â Environment Variable Error
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
đ¨ Required environment variables are not set!
Your application needs these variables to run properly.
Missing Variables:
âĸ DATABASE_URL
âĸ API_KEY
đĄ Suggestions:
â Create a .env file in your project root if it doesn't exist
â Add the following variables to your .env file:
DATABASE_URL=your_value_here
API_KEY=your_value_here
â Make sure your .env file is in the project root directory
â Example: DATABASE_URL=postgresql://user:pass@localhost:5432/db
â Example: API_KEY=your_secret_key_here
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
âšī¸ Need help? Check the documentation:
https://github.com/anandanpm/env-guard#readme
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
```
## đ Quick Start
### Installation
```bash
npm install envkeeper
```
### Basic Usage
```javascript
const envKeeper = require('envkeeper');
// At the top of your app entry point (index.js, app.js, etc.)
// Require critical environment variables - app won't start without them
envKeeper.require(['DATABASE_URL', 'API_KEY', 'JWT_SECRET']);
// Validate with type checking
envKeeper.validate({
PORT: 'port', // Must be a valid port number (1-65535)
API_URL: 'url', // Must be a valid URL
ADMIN_EMAIL: 'email', // Must be a valid email
DEBUG: 'boolean' // Must be true/false/1/0
});
// Get variable with default value
const port = envKeeper.get('PORT', 3000);
const environment = envKeeper.get('NODE_ENV', 'development');
```
## \ud83d\udcda Complete API Documentation
### `require(vars: string[])`
Require specific environment variables to be set. Throws an error with helpful suggestions if any are missing.
```javascript
envKeeper.require(['DATABASE_URL', 'API_KEY']);
```
**When to use:** At application startup for critical variables your app can't run without.
### `validate(schema: Object)`
Validate environment variables with comprehensive type checking and rules.
```javascript
envKeeper.validate({
// Simple type validation
PORT: 'port',
API_URL: 'url',
ADMIN_EMAIL: 'email',
DEBUG: 'boolean',
TIMEOUT: 'number',
CONFIG: 'json',
// Advanced validation with rules
API_KEY: {
type: 'string',
minLength: 32,
maxLength: 64
},
NODE_ENV: {
enum: ['development', 'staging', 'production']
},
VERSION: {
pattern: '^\\d+\\.\\d+\\.\\d+$' // Semantic versioning
}
});
```
**Supported Types:**
- `string` - Any string value
- `number` - Numeric value (e.g., "42", "3.14")
- `boolean` - true/false/1/0
- `url` - Valid URL (e.g., "https://example.com")
- `email` - Valid email address
- `json` - Valid JSON string
- `port` - Valid port number (1-65535)
**Validation Rules:**
- `type` - Data type validation
- `minLength` - Minimum string length
- `maxLength` - Maximum string length
- `pattern` - Regular expression pattern
- `enum` - List of allowed values
### `get(varName: string, defaultValue?: any, validation?: string | Object)`
Get an environment variable with optional default value and validation.
```javascript
// Simple get with default
const port = envKeeper.get('PORT', 3000);
// Get with validation
const apiKey = envKeeper.get('API_KEY', null, {
type: 'string',
minLength: 20
});
// Throws error if variable is missing and no default provided
const requiredVar = envKeeper.get('REQUIRED_VAR');
```
**When to use:** When you want a single variable with a fallback value, or when you want to validate inline.
### `check(vars: string[])`
Check if variables are set without throwing an error. Returns a status object.
```javascript
const status = envKeeper.check(['DATABASE_URL', 'API_KEY', 'OPTIONAL_VAR']);
console.log(status);
// {
// valid: false,
// missing: ['API_KEY'],
// set: ['DATABASE_URL', 'OPTIONAL_VAR']
// }
if (!status.valid) {
console.warn(`Missing variables: ${status.missing.join(', ')}`);
}
```
**When to use:** For optional variables or when you want to handle missing variables gracefully without throwing.
---
### `printStatus(vars: string[])`
Print a beautiful formatted status of environment variables (useful for debugging).
```javascript
envKeeper.printStatus(['DATABASE_URL', 'API_KEY', 'DEBUG', 'OPTIONAL_VAR']);
```
**Output:**
```
Environment Variables Status:
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â DATABASE_URL: SET
â API_KEY: SET
â DEBUG: SET
â OPTIONAL_VAR: MISSING
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
```
### `list(hideValues?: boolean)`
List all environment variables (useful for debugging, values hidden by default for security).
```javascript
const allVars = envKeeper.list(); // Values hidden
const allVarsVisible = envKeeper.list(false); // Values visible
```
### `addCustomValidator(typeName, validator, errorMessage?)`
Add your own custom validation types for specific business needs.
```javascript
// Simple custom validator
envKeeper.addCustomValidator(
'phone',
(value) => /^\d{10}$/.test(value),
'"{value}" is not a valid 10-digit phone number. Example: 1234567890'
);
// Use it like built-in types
envKeeper.validate({ PHONE_NUMBER: 'phone' });
```
### `addCustomValidators(validators)`
Register multiple custom validators at once.
```javascript
envKeeper.addCustomValidators({
phone: {
validate: (value) => /^\d{10}$/.test(value),
errorMessage: 'Must be 10 digits'
},
zipcode: {
validate: (value) => /^\d{5}$/.test(value),
errorMessage: 'Must be 5 digits'
},
ipv4: (value) => {
const parts = value.split('.');
return parts.length === 4 && parts.every(p => {
const num = parseInt(p);
return num >= 0 && num <= 255;
});
}
});
```
**Common Custom Validator Examples:**
```javascript
// AWS Region validator
envKeeper.addCustomValidator('awsregion', (value) => {
const regions = ['us-east-1', 'us-west-1', 'eu-west-1'];
return regions.includes(value);
});
// Strong password validator
envKeeper.addCustomValidator('strongpassword', (value) => {
return value.length >= 8 &&
/[A-Z]/.test(value) &&
/[a-z]/.test(value) &&
/[0-9]/.test(value) &&
/[!@#$%^&*]/.test(value);
});
// Hex color validator
envKeeper.addCustomValidator('hexcolor',
(value) => /^#[0-9A-Fa-f]{6}$/.test(value)
);
// Slug validator (URL-friendly)
envKeeper.addCustomValidator('slug',
(value) => /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(value)
);
```
### `removeCustomValidator(typeName)`
Remove a custom validator.
```javascript
envKeeper.removeCustomValidator('phone');
```
### `getCustomValidators()`
Get list of all registered custom validators.
```javascript
const customTypes = envKeeper.getCustomValidators();
console.log('Custom types:', customTypes); // ['phone', 'zipcode', 'ipv4']
```
## đ¯ Real-World Examples
### Express.js Application
```javascript
const express = require('express');
const envKeeper = require('envkeeper');
// Validate environment at startup
try {
envKeeper.validate({
PORT: 'port',
DATABASE_URL: 'url',
JWT_SECRET: { type: 'string', minLength: 32 },
NODE_ENV: { enum: ['development', 'production', 'test'] },
SMTP_HOST: 'string',
SMTP_PORT: 'port',
ADMIN_EMAIL: 'email'
});
console.log('\u2705 Environment variables validated successfully!');
} catch (error) {
console.error(error.toString());
process.exit(1);
}
const app = express();
const port = envKeeper.get('PORT', 3000);
// Your app code...
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});
```
### Microservice Configuration
```javascript
const envKeeper = require('envkeeper');
// Required variables that must exist
envKeeper.require([
'SERVICE_NAME',
'DATABASE_URL',
'REDIS_URL',
'API_KEY'
]);
// Validate all configurations
envKeeper.validate({
PORT: 'port',
DATABASE_URL: 'url',
REDIS_URL: 'url',
MAX_CONNECTIONS: 'number',
ENABLE_CACHE: 'boolean',
LOG_LEVEL: { enum: ['debug', 'info', 'warn', 'error'] }
});
// Use the values
const config = {
port: envKeeper.get('PORT', 8080),
database: process.env.DATABASE_URL,
redis: process.env.REDIS_URL,
maxConnections: Number(envKeeper.get('MAX_CONNECTIONS', 10)),
enableCache: process.env.ENABLE_CACHE === 'true'
};
module.exports = config;
```
### Docker & CI/CD
```javascript
const envKeeper = require('envkeeper');
// Check optional CI/CD specific variables
const ciStatus = envKeeper.check([
'CI',
'GITHUB_ACTIONS',
'DOCKER_BUILD'
]);
if (ciStatus.valid) {
console.log('Running in CI/CD environment');
}
// Required for deployment
if (process.env.NODE_ENV === 'production') {
envKeeper.validate({
DATABASE_URL: 'url',
API_KEY: { type: 'string', minLength: 32 },
ALLOWED_ORIGINS: 'string',
SENTRY_DSN: 'url'
});
}
```
## \ud83c\udd9a\ufe0f EnvKeeper vs Others
### EnvKeeper vs dotenv
| Feature | EnvKeeper | dotenv |
|---------|-----------|--------|
| **Load .env files** | â (use dotenv first) | â
|
| **Validation** | â
Comprehensive | â None |
| **Type checking** | â
7+ types | â None |
| **Error messages** | â
Beautiful & actionable | N/A |
| **Fail fast** | â
At startup | â Runtime failures |
| **Smart suggestions** | â
Context-aware | â None |
**Use together:**
```javascript
require('dotenv').config(); // Load .env file
const envKeeper = require('envkeeper');
envKeeper.require(['DATABASE_URL', 'API_KEY']); // Validate
```
### EnvKeeper vs envalid
| Feature | EnvKeeper | envalid |
|---------|-----------|---------|
| **Error messages** | â
Colorful & formatted | â Plain text |
| **Suggestions** | â
Actionable guidance | â Basic errors |
| **Learning curve** | â
Simple API | â ī¸ More complex |
| **Zero dependencies** | â
| â
|
| **TypeScript** | â
| â
|
| **Status display** | â
`printStatus()` | â |
### EnvKeeper vs env-var
| Feature | EnvKeeper | env-var |
|---------|-----------|---------|
| **Batch validation** | â
Validate many at once | â ī¸ One by one |
| **Error formatting** | â
Beautiful output | â Basic |
| **Suggestions** | â
Smart hints | â None |
| **Pattern matching** | â
Regex support | â
|
| **Enum validation** | â
| â
|
## \ud83e\udde0 Smart Error Messages
EnvKeeper analyzes your variable names and provides relevant examples:
```javascript
// Missing PORT variable
envKeeper.require(['PORT']);
// Suggestion includes: "Example: PORT=3000"
// Missing DATABASE_URL
envKeeper.require(['DATABASE_URL']);
// Suggestion includes: "Example: DATABASE_URL=postgresql://user:pass@localhost:5432/db"
// Missing API_KEY
envKeeper.require(['API_KEY']);
// Suggestion includes: "Example: API_KEY=your_secret_key_here"
// Invalid port number
envKeeper.validate({ PORT: 'port' });
// Error: "abc" is not a valid port number (1-65535). Example: 3000
// Invalid URL
envKeeper.validate({ API_URL: 'url' });
// Error: "not-a-url" is not a valid URL. Example: https://example.com
```
## \ud83d\udee0\ufe0f Best Practices
### 1. Validate at Application Startup
```javascript
// index.js or app.js
require('dotenv').config();
const envKeeper = require('envkeeper');
// Fail fast - validate before anything else
envKeeper.validate({
DATABASE_URL: 'url',
API_KEY: { type: 'string', minLength: 32 },
PORT: 'port'
});
// Rest of your application code...
```
### 2. Use `require()` for Critical Variables
```javascript
// These variables are absolutely required
envKeeper.require(['DATABASE_URL', 'JWT_SECRET', 'API_KEY']);
// Optional variables can use get() with defaults
const logLevel = envKeeper.get('LOG_LEVEL', 'info');
```
### 3. Combine with dotenv
```javascript
// Load .env file first
require('dotenv').config();
// Then validate
const envKeeper = require('envkeeper');
envKeeper.validate({ /* your schema */ });
```
### 4. Different Validation for Different Environments
```javascript
const envKeeper = require('envkeeper');
// Base configuration (all environments)
envKeeper.require(['NODE_ENV', 'PORT']);
// Production-specific
if (process.env.NODE_ENV === 'production') {
envKeeper.validate({
DATABASE_URL: 'url',
REDIS_URL: 'url',
API_KEY: { type: 'string', minLength: 32 },
SENTRY_DSN: 'url'
});
}
// Development-specific
if (process.env.NODE_ENV === 'development') {
envKeeper.validate({
DATABASE_URL: 'url',
DEBUG: 'boolean'
});
}
```
### 5. Use `printStatus()` for Debugging
```javascript
if (process.env.DEBUG === 'true') {
envKeeper.printStatus([
'DATABASE_URL',
'API_KEY',
'REDIS_URL',
'SMTP_HOST'
]);
}
```
## \ud83d\udcdd Example .env File
```env
# Server Configuration
PORT=3000
NODE_ENV=development
# Database
DATABASE_URL=postgresql://user:password@localhost:5432/myapp
# Redis
REDIS_URL=redis://localhost:6379
# API Keys
API_KEY=your_secret_api_key_here_min_32_chars
JWT_SECRET=your_jwt_secret_here_at_least_32_characters
# Email Configuration
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your-email@gmail.com
SMTP_PASS=your-password
ADMIN_EMAIL=admin@example.com
# Feature Flags
ENABLE_CACHE=true
DEBUG=false
LOG_LEVEL=info
# External Services
STRIPE_SECRET_KEY=sk_test_your_stripe_key
SENTRY_DSN=https://your-sentry-dsn@sentry.io/project
# Allowed Values
ENVIRONMENT=development
# Valid: development, staging, production
```
## \ud83d\udc1b Error Handling
### Catching Errors
```javascript
const envKeeper = require('envkeeper');
try {
envKeeper.validate({
PORT: 'port',
API_URL: 'url'
});
} catch (error) {
if (error.name === 'EnvKeeperError') {
// Access error details
console.log('Missing:', error.missing);
console.log('Invalid:', error.invalid);
console.log('Suggestions:', error.suggestions);
// Print formatted message
console.error(error.toString());
// Exit or handle gracefully
process.exit(1);
}
}
```
### Custom Error Handling
```javascript
const envKeeper = require('envkeeper');
function validateEnvironment() {
try {
envKeeper.validate({
DATABASE_URL: 'url',
API_KEY: { type: 'string', minLength: 32 }
});
return { success: true };
} catch (error) {
if (error.name === 'EnvKeeperError') {
return {
success: false,
missing: error.missing,
invalid: error.invalid,
message: error.message
};
}
throw error;
}
}
const result = validateEnvironment();
if (!result.success) {
console.error('Environment validation failed');
console.error('Missing:', result.missing);
console.error('Invalid:', result.invalid);
// Send to monitoring service, log, etc.
}
```
## \ud83d\udcbb TypeScript Support
EnvKeeper includes full TypeScript definitions:
```typescript
import envKeeper, { EnvKeeper, EnvKeeperError, ValidationRule } from 'envkeeper';
// Type-safe validation
const schema: Record<string, string | ValidationRule> = {
PORT: 'port',
API_URL: 'url',
API_KEY: {
type: 'string',
minLength: 32
}
};
try {
envKeeper.validate(schema);
} catch (error) {
if (error instanceof EnvKeeperError) {
console.error(error.missing);
console.error(error.invalid);
console.error(error.suggestions);
}
}
```
## \ud83e\udd14 FAQ
**Q: Do I still need dotenv?**\nA: Yes! EnvKeeper validates environment variables but doesn't load .env files. Use `dotenv` to load files, then `envKeeper` to validate.
**Q: Will this slow down my application?**\nA: No! EnvKeeper validates once at startup. The overhead is negligible (milliseconds) and prevents costly runtime errors.
**Q: Can I use this in production?**\nA: Absolutely! EnvKeeper is designed for production use. It helps catch configuration issues before they cause outages.
**Q: What if I have a lot of environment variables?**\nA: EnvKeeper handles validation for any number of variables efficiently. The formatted errors make it easy to fix multiple issues at once.
**Q: Can I disable colored output?**\nA: Yes! Colors are automatically disabled when output is piped or in non-TTY environments (like CI/CD logs).
**Q: How do I validate nested JSON in environment variables?**\nA: Use the 'json' type:
```javascript
envKeeper.validate({ CONFIG: 'json' });
const config = JSON.parse(process.env.CONFIG);
```
## \ud83d\udcdd License
MIT Š [Anandakrishnan PM](https://github.com/anandanpm)
## \ud83d\udc96 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
1. Fork the repository
2. Create your feature branch (`git checkout -b feature/AmazingFeature`)
3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)
4. Push to the branch (`git push origin feature/AmazingFeature`)
5. Open a Pull Request
## \u2b50 Star History
If you find EnvKeeper helpful, please consider giving it a star on GitHub!
## \ud83d\udce6 Links
- [npm package](https://www.npmjs.com/package/envkeeper)
- [GitHub repository](https://github.com/anandanpm/env-guard)
- [Issue tracker](https://github.com/anandanpm/env-guard/issues)
- [Changelog](https://github.com/anandanpm/env-guard/releases)
**Made with \u2764\ufe0f for developers who deserve better error messages**