UNPKG

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
# đŸ›Ąī¸ EnvKeeper [![npm version](https://badge.fury.io/js/envkeeper.svg)](https://badge.fury.io/js/envkeeper) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Node.js Version](https://img.shields.io/badge/node-%3E%3D12.0.0-brightgreen)](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**