{"id":26979817,"url":"https://github.com/bytehide/dotsecrets","last_synced_at":"2026-03-02T03:03:56.548Z","repository":{"id":285929989,"uuid":"959788931","full_name":"bytehide/dotsecrets","owner":"bytehide","description":"The next generation of environment variables management. A supercharged dotenv alternative with validation, type safety, and seamless cloud provider integration.","archived":false,"fork":false,"pushed_at":"2025-04-03T17:55:10.000Z","size":4176,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-10-23T17:29:02.889Z","etag":null,"topics":["aws","azure","bytehide","doppler","dotenv","environment-variables","google-cloud","hashicorp","javascript","nodejs","secret-management","secrets","typescript"],"latest_commit_sha":null,"homepage":"https://bytehide.com/products/secrets-manager","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bytehide.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-04-03T11:03:02.000Z","updated_at":"2025-04-05T18:12:38.000Z","dependencies_parsed_at":"2025-04-09T15:58:02.875Z","dependency_job_id":"9870434b-ddd3-4e7b-911d-2c4a0e9a6720","html_url":"https://github.com/bytehide/dotsecrets","commit_stats":null,"previous_names":["bytehide/dotsecrets"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/bytehide/dotsecrets","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bytehide%2Fdotsecrets","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bytehide%2Fdotsecrets/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bytehide%2Fdotsecrets/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bytehide%2Fdotsecrets/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bytehide","download_url":"https://codeload.github.com/bytehide/dotsecrets/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bytehide%2Fdotsecrets/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29991299,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-02T01:47:34.672Z","status":"online","status_checked_at":"2026-03-02T02:00:07.342Z","response_time":60,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws","azure","bytehide","doppler","dotenv","environment-variables","google-cloud","hashicorp","javascript","nodejs","secret-management","secrets","typescript"],"created_at":"2025-04-03T14:19:12.564Z","updated_at":"2026-03-02T03:03:56.527Z","avatar_url":"https://github.com/bytehide.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# DotSecrets\n\nBeyond environment variables: a complete secrets ecosystem for local development and cloud production.\n\n[![npm version](https://img.shields.io/npm/v/dotsecrets.svg)](https://www.npmjs.com/package/dotsecrets)\n[![npm downloads](https://img.shields.io/npm/dm/dotsecrets.svg)](https://www.npmjs.com/package/dotsecrets)\n[![License](https://img.shields.io/npm/l/dotsecrets.svg)](https://github.com/bytehide/dotsecrets/blob/main/LICENSE)\n[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-%230074c1.svg)](https://www.typescriptlang.org/)\n[![GitHub stars](https://img.shields.io/github/stars/bytehide/dotsecrets.svg?style=social)](https://github.com/bytehide/dotsecrets/stargazers)\n[![GitHub forks](https://img.shields.io/github/forks/bytehide/dotsecrets.svg?style=social)](https://github.com/bytehide/dotsecrets/fork)\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://twitter.com/intent/tweet?text=Check%20out%20DotSecrets%20-%20The%20next%20generation%20of%20environment%20variables%20management%20with%20validation%2C%20type%20safety%2C%20and%20cloud%20provider%20integration.\u0026url=https://github.com/bytehide/dotsecrets\u0026hashtags=javascript,nodejs,dotenv,security,programming\" target=\"_blank\"\u003e\n    \u003cimg src=\"https://img.shields.io/twitter/url/http/shields.io.svg?style=social\" alt=\"Tweet\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://www.linkedin.com/sharing/share-offsite/?url=https://github.com/bytehide/dotsecrets\" target=\"_blank\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/Share-LinkedIn-blue?style=social\u0026logo=linkedin\" alt=\"Share on LinkedIn\" /\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n**The next generation of environment variables management.** DotSecrets takes everything you love about dotenv and supercharges it for modern applications. Use local files during development and seamlessly connect to any secrets provider in production – all with zero code changes.\n\n**DotSecrets = dotenv + external providers + validation + type safety + encryption + IDE autocompletion**\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"50%\" valign=\"top\"\u003e\n      \u003cdiv align=\"center\"\u003e\n      \u003cimg src=\"./docs/images/dotsecrets%20schema.png\" alt=\"DotSecrets Schema\" width=\"60%\" style=\"max-height: 200px; object-fit: contain;\"\u003e\n      \u003c/div\u003e\n    \u003c/td\u003e\n    \u003ctd width=\"50%\" valign=\"top\"\u003e\n      \u003ch2\u003eKey Features\u003c/h2\u003e\n      \u003cul\u003e\n        \u003cli\u003e✨ \u003cstrong\u003eDrop-in dotenv replacement with superpowers\u003c/strong\u003e\u003c/li\u003e\n        \u003cli\u003e🚀 \u003cstrong\u003eLocal to cloud with zero code changes\u003c/strong\u003e\u003c/li\u003e\n        \u003cli\u003e🛡️ \u003cstrong\u003ePrevent app crashes from missing secrets\u003c/strong\u003e\u003c/li\u003e\n        \u003cli\u003e🔄 \u003cstrong\u003eAuto-convert strings to numbers, booleans, JSON\u003c/strong\u003e\u003c/li\u003e\n        \u003cli\u003e💡 \u003cstrong\u003eNever mistype a secret name again\u003c/strong\u003e\u003c/li\u003e\n        \u003cli\u003e🔌 \u003cstrong\u003eAWS, Azure, ByteHide, HashiCorp — one command\u003c/strong\u003e\u003c/li\u003e\n        \u003cli\u003e🔒 \u003cstrong\u003ePush secrets securely to production\u003c/strong\u003e\u003c/li\u003e\n      \u003c/ul\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n## 📋 Table of Contents\n\n- [1. 🌱 Install](#1--install)\n- [2. 🚀 Getting Started](#2--getting-started)\n- [3. 🔄 Migrating from dotenv](#3--migrating-from-dotenv)\n- [4. 🏗️ Core Features](#4-️-core-features)\n  - [Multiple ENV Files](#multiple-env-files)\n  - [Environment-Specific Files](#environment-specific-files)\n  - [Push Secrets to Production](#push-secrets-to-production)\n  - [Asynchronous-First Approach](#asynchronous-first-approach)\n  - [Powerful Validation \\\u0026 Type Conversion](#powerful-validation--type-conversion)\n  - [External Secrets Providers](#external-secrets-providers)\n    - [Zero-code production configuration](#zero-code-production-configuration)\n  - [Variable Expansion](#variable-expansion)\n  - [Public Secrets](#public-secrets)\n  - [Auto-reloading \\\u0026 File Watching](#auto-reloading--file-watching)\n  - [IDE Autocompletion](#ide-autocompletion)\n  - [Encryption Support](#encryption-support)\n- [5. 🔌 Secrets Providers](#5--secrets-providers)\n  - [Provider Configuration](#provider-configuration)\n    - [Environment Variables (Default)](#environment-variables-default)\n    - [ByteHide Secrets](#bytehide-secrets)\n    - [AWS Secrets Manager](#aws-secrets-manager)\n    - [Azure Key Vault](#azure-key-vault)\n    - [Google Cloud Secret Manager](#google-cloud-secret-manager)\n    - [HashiCorp Vault](#hashicorp-vault)\n    - [IBM Cloud Secrets Manager](#ibm-cloud-secrets-manager)\n    - [1Password](#1password)\n    - [Keeper Secrets Manager](#keeper-secrets-manager)\n    - [Doppler](#doppler)\n- [6. 🛠️ Common Usage Patterns](#6-️-common-usage-patterns)\n- [7. ⚙️ Configuration](#7-️-configuration)\n- [8. 🛠️ CLI Tools](#8-️-cli-tools)\n- [9. 🔬 Advanced Usage](#9--advanced-usage)\n- [10. ❓ FAQ \\\u0026 Troubleshooting](#10--faq--troubleshooting)\n- [11. 📚 API Reference](#11--api-reference)\n- [12. 💪 Contributing \u0026 Community](#12--contributing--community)\n\n## 1. 🌱 Install\n\n```bash\n# npm\nnpm install dotsecrets\n\n# yarn\nyarn add dotsecrets\n\n# pnpm\npnpm add dotsecrets\n```\n\n## 2. 🚀 Getting Started\n\nDotSecrets is designed to be **plug-and-play**. Unlike other libraries, it requires no manual initialization in your code. Simply install it and start using it right away.\n\n### Just import and use\n\n```javascript\n// Just import the secrets object and start using it\nimport { secrets } from 'dotsecrets';\n\n// RECOMMENDED: Always use the async pattern with await\nasync function getApiClient() {\n  const endpoint = await secrets.API_ENDPOINT;\n  const key = await secrets.API_KEY.required();\n  \n  return new ApiClient(endpoint, key);\n}\n```\n\n### Create configuration files (optional)\n\nIf you don't have `.env` or `.secrets` files yet, you can easily set them up:\n\n```bash\n# Creates .env, .secrets, and adds them to .gitignore\nnpx dotsecrets setup\n```\n\n### No manual initialization needed\n\nDotSecrets automatically loads your environment variables and secrets on import. You don't need to call any initialization functions like with dotenv:\n\n```javascript\n// ❌ NOT needed with DotSecrets\n// import dotenv from 'dotenv';\n// dotenv.config();\n\n// ✅ Just import and use\nimport { secrets } from 'dotsecrets';\n```\n\n### The async-first approach\n\nAlways use the asynchronous pattern with `await` for the most reliable access to your secrets:\n\n```javascript\n// ✅ Recommended: Async pattern\nconst apiKey = await secrets.API_KEY;\nconst isDebug = await secrets.DEBUG_MODE.boolean();\nconst serverPort = await secrets.PORT.number().min(1000);\n\n// ❌ Avoid using the synchronous pattern unless absolutely necessary\n// const apiKey = secrets.API_KEY; // Not recommended without preloadAllSecrets()\n```\n\n### For legacy code (optional)\n\nOnly in cases where async/await cannot be used, you can preload secrets at application startup:\n\n```javascript\nimport { preloadAllSecrets, secrets } from 'dotsecrets';\n\n// At application startup:\nawait preloadAllSecrets();\n\n// Then in synchronous code:\nfunction getLegacyConfig() {\n  return secrets.API_KEY; // Works after preloading\n}\n```\n\n## 3. 🔄 Migrating from dotenv\n\nAlready using dotenv? DotSecrets makes it easy to upgrade to a more powerful secrets management solution while maintaining compatibility.\n\n![DotSecrets Autocomplete](./docs/images/dotsecrets-vs-dotenv.png)\n\n### Automatic migration\n\nYou can quickly migrate from dotenv to DotSecrets using the migrate command:\n\n```bash\nnpx dotsecrets migrate\n```\n\nThis command:\n\n- Handles your existing `.env` files\n- Sets up DotSecrets configuration\n- Adds appropriate entries to `.gitignore`\n- Generates TypeScript definitions for IDE autocompletion\n\n### Full compatibility with process.env\n\nDotSecrets maintains full compatibility with `process.env`, so your existing code will continue to work:\n\n```javascript\n// This still works - no changes needed for existing code\nconst apiUrl = process.env.API_URL;\n```\n\nAll variables from `.env`, `.secrets`, and `.public` files are automatically loaded into `process.env`, just like with dotenv.\n\n### Benefits of switching to secrets.KEY pattern\n\nWhile DotSecrets maintains compatibility with `process.env`, you gain significant advantages by migrating to the `secrets.KEY` pattern:\n\n| Feature | process.env.KEY | secrets.KEY |\n|---------|-----------------|-------------|\n| Type safety | ❌ Always string or undefined | ✅ Type conversion (number, boolean, JSON) |\n| Validation | ❌ Manual validation required | ✅ Built-in validation chains |\n| Error handling | ❌ Silent undefined errors | ✅ Clear error messages |\n| Asynchronous loading | 🫠 Don't apply | ✅ Async providers supported |\n| Default values | ❌ Manual defaulting | ✅ Built-in `.default()` method |\n| IDE autocompletion | ❌ No key suggestions | ✅ Full autocompletion support |\n| Production-ready | ❌ Local-only solution | ✅ Seamless transition to cloud providers |\n| Provider switching | ❌ Code changes required | ✅ Zero code changes when switching providers |\n| Frontend access | ❌ Not available in browser | ✅ `secrets.PUBLIC_*` works in frontend code |\n\n#### Production-ready secret management\n\nUsing `secrets.KEY` makes your application immediately ready for production environments:\n\n```javascript\n// Your code stays EXACTLY THE SAME when moving from development to production\nasync function getApiClient() {\n  const apiKey = await secrets.API_KEY.required();\n  // ...\n}\n```\n\nYou can start with local `.env` files during development, then seamlessly switch to AWS Secrets Manager, Azure Key Vault, ByteHide Secrets, Google Cloud Secret Manager, or any other provider in production - **without changing a single line of application code**. DotSecrets handles the provider configuration separately from your business logic.\n\n#### Seamless provider switching\n\nWith process.env:\n\n```javascript\n// Hard-coded to use environment variables\nconst apiKey = process.env.API_KEY;\n// Must rewrite code to use a different provider\n```\n\nWith DotSecrets:\n\n```javascript\n// Works with ANY provider - local files, ByteHide, Azure, AWS, Google Cloud, etc.\nconst apiKey = await secrets.API_KEY;\n```\n\nSimply configure your preferred provider with `npx dotsecrets setup` and your application will automatically retrieve secrets from the right source, regardless of environment.\n\n### Migration example\n\nBefore (with dotenv):\n\n```javascript\n// Manual validation, type conversion, and error handling\nconst port = process.env.PORT ? parseInt(process.env.PORT, 10) : 3000;\nif (isNaN(port) || port \u003c 1000 || port \u003e 9999) {\n  throw new Error('PORT must be a number between 1000 and 9999');\n}\n\nconst apiKey = process.env.API_KEY;\nif (!apiKey) {\n  throw new Error('API_KEY is required');\n}\n```\n\nAfter (with DotSecrets):\n\n```javascript\n// Built-in validation, type conversion, and error handling\nconst port = await secrets.PORT.number().between(1000, 9999).default(3000);\nconst apiKey = await secrets.API_KEY.required();\n```\n\n## 4. 🏗️ Core Features\n\n### Multiple ENV Files\n\n![DotSecrets Workflow Schema](./docs/images/dotsecrets%20files%20schema.png)\n\nDotSecrets manages different types of configuration files:\n\n| File | Purpose | In Git? | Example Values |\n|------|---------|---------|---------------|\n| `.secrets` | Sensitive information | ❌ No | Passwords, API keys, tokens |\n| `.env` | Development variables | ❌ No | Local hostnames, debug flags |\n| `.public` | Non-sensitive config | ✅ Yes | Public URLs, feature flags (with `PUBLIC_` prefix) |\n\n\u003e ⚠️ **Note**: Using `.secrets` is optional - you can continue using `.env` files like with dotenv. However, the separate files provide better organization: `.secrets` clearly indicates sensitive information, `.env` can contain mixed values, and `.public` explicitly marks values safe for version control. This naming convention helps prevent accidental exposure of sensitive data.\n\n### Environment-Specific Files\n\nAutomatically load environment-specific configurations:\n\n```bash\n.secrets         # Base secrets for all environments\n.secrets.staging # Overrides for staging environment\n.secrets.production # Overrides for production\n```\n\n\u003e The same with .env and .public files\n\nSet your environment with `NODE_ENV` or explicitly in configuration.\n\n### Push Secrets to Production\n\n![DotSecrets Push](./docs/images/dotsecrets-push.png)\n\nDotSecrets makes it easy to sync your local secrets to production environments without ever exposing them in version control:\n\n```bash\nnpx dotsecrets push\n```\n\nThis interactive command:\n\n1. Scans for all available `.secrets` and `.env` files\n2. Lets you select which file to push from\n3. Allows you to exclude specific secrets from being pushed\n4. Guides you through selecting a destination provider (AWS, Azure, ByteHide, etc.)\n5. Securely uploads your secrets to the selected provider\n\nThis seamless workflow ensures your development and production environments stay in sync while maintaining the highest security standards - your secrets never need to pass through git or any other intermediary.\n\n### Asynchronous-First Approach\n\nDotSecrets is designed with modern JavaScript in mind:\n\n```javascript\n// RECOMMENDED: Clean async access pattern\nasync function initializeApi() {\n  const endpoint = await secrets.API_ENDPOINT;\n  const key = await secrets.API_KEY.required();\n  const timeout = await secrets.TIMEOUT.number().default(5000);\n  \n  return new ApiClient(endpoint, key, { timeout });\n}\n\n// Only for legacy code: Synchronous access pattern\n// Requires preloading secrets at application startup\nif (needsSynchronousAccess) {\n  await preloadAllSecrets();\n  const apiKey = secrets.API_KEY; // Only works after preload\n}\n```\n\n### Powerful Validation \u0026 Type Conversion\n\nEnsure your secrets meet your requirements:\n\n```javascript\n// Convert to number with range validation\nconst port = await secrets.PORT.number().between(1000, 9999);\n\n// Required values\nconst apiKey = await secrets.API_KEY.required();\n\n// String validation\nconst email = await secrets.EMAIL.trim().regex(/^[\\w.-]+@[\\w.-]+\\.\\w+$/);\n\n// Boolean conversion with validation\nconst enabled = await secrets.FEATURE_FLAG.boolean().true();\n\n// JSON parsing with type safety\nconst config = await secrets.CONFIG.json();\n```\n\n### External Secrets Providers\n\nConnect to external providers with simple configuration:\n\n- Environment variables (built-in)\n- ByteHide Secrets\n- AWS Secrets Manager\n- Azure Key Vault\n- Google Cloud Secret Manager\n- HashiCorp Vault\n- 1Password\n- And more...\n\n#### Zero-code production configuration\n\nIn production environments, you can automatically load secrets from external providers without changing your code. Simply set environment variables to configure the provider:\n\n```bash\n# Example: Use IBM Cloud Secrets Manager in production\nDOTSECRETS_PLUGIN=ibm\nIBM_CLOUD_API_KEY=your-api-key\nIBM_SECRETS_MANAGER_URL=your-instance-url\n\n# Example: Use AWS Secrets Manager\nDOTSECRETS_PLUGIN=aws\nAWS_REGION=us-east-1\nAWS_ACCESS_KEY_ID=your-access-key\nAWS_SECRET_ACCESS_KEY=your-secret-key\n\n# Example: Use ByteHide Secrets\nDOTSECRETS_PLUGIN=bytehide\nBYTEHIDE_SECRETS_TOKEN=your-token\n```\n\nYour application will automatically load secrets from the configured provider in production while continuing to use local `.env` and `.secrets` files in development – all without changing a single line of code.\n\n\u003e [🔗 See all available providers and their configuration options](#7-secrets-providers)\n\u003e\n### Variable Expansion\n\nDotSecrets supports referencing other variables within your configuration:\n\n```bash\n# Variable references are automatically expanded\nPASSWORD=super-secret-password\nDATABASE_URL=postgresql://user:${PASSWORD}@localhost:5432/mydb\n\n# Works across different files too\nAPI_VERSION=v1\nPUBLIC_API_ENDPOINT=https://api.example.com/${API_VERSION}\n```\n\nEnable variable expansion with:\n\n```javascript\nconfig({ expand: true });\n```\n\nOr just set `DOTSECRETS_EXPAND=true` in your environment.\n\n### Public Secrets\n\nValues prefixed with `PUBLIC_` are considered non-sensitive and can be safely exposed to frontend code:\n\n```bash\n# .public file (can be committed to git)\nPUBLIC_API_VERSION=v2\nPUBLIC_FEATURE_FLAGS={\"darkMode\":true,\"beta\":false}\n```\n\nPublic secrets:\n\n- Can be stored in the `.public` file (safe to commit to git)\n- Are always loaded locally, never from external providers\n- Can be accessed synchronously without await (even without preload)\n\n```javascript\n// Access public values without await\nconst apiVersion = secrets.PUBLIC_API_VERSION;\nconst features = secrets.PUBLIC_FEATURE_FLAGS.json();\n\n// In frontend code\nconsole.log(\"Using API version:\", secrets.PUBLIC_API_VERSION);\n```\n\n### Auto-reloading \u0026 File Watching\n\nAutomatically detect changes to configuration files in development:\n\n```javascript\n// Enable file watching\nconfig({ watch: true });\n```\n\nWhen changes are detected, secrets are reloaded and optional update scripts are executed.\n\n### IDE Autocompletion\n\n![DotSecrets Autocomplete](./docs/images/dotsecrets-autocomplete.png)\n\nGenerate TypeScript definitions for your secrets:\n\n```bash\n# Generate type definitions for IDE autocompletion\nnpx dotsecrets sync-ide\n```\n\nGet full IntelliSense support for available secrets and chainable methods.\n\n### Encryption Support\n\nDotSecrets includes support for encrypting `.secrets` files:\n\n```javascript\n// Load with encryption key\nconfig({ encryptionKey: process.env.DOTSECRETS_ENCRYPTION_KEY });\n```\n\n\u003e **Note**: While encryption is available, we recommend using dedicated secrets management providers rather than storing encrypted secrets in version control. The `push` command provides a more secure way to synchronize secrets between environments without exposing them, even in encrypted form.\n\u003e\n\u003e For production environments, consider services like AWS Secrets Manager, Azure Key Vault, ByteHide Secrets, or HashiCorp Vault, which offer additional security features such as access auditing, rotation policies, and fine-grained permissions.\n\n## 5. 🔌 Secrets Providers\n\nDotSecrets supports multiple secrets providers, allowing you to store your secrets in different systems while maintaining a consistent access pattern in your code.\n\n\u003e ⚠️ **Important Warning**: Local variables in `.env` or `.secrets` files always take precedence over external providers. If you want to retrieve a secret like `API_KEY` from AWS Secrets Manager (or any other provider), make sure you do not define that same variable in your local `.env` or `.secrets` files, and do not deploy these files to production servers. If the variable exists locally, it will override the one from your configured provider, which can lead to unexpected behavior in production environments.\n\n### Available Providers\n\n| Provider | Plugin ID | Type | Support |\n|----------|-----------|------|---------|\n| Environment Variables | `env` | Local | ✅ |\n| ByteHide Secrets | `bytehide` | Cloud | ✅ |\n| AWS Secrets Manager | `aws` | Cloud | ✅ |\n| Azure Key Vault | `azure` | Cloud | ✅ |\n| Google Cloud Secret Manager | `gcp` | Cloud | ✅ |\n| HashiCorp Vault | `hashicorp` | Self-hosted/Cloud | ✅ |\n| IBM Cloud Secrets Manager | `ibm` | Cloud | ✅ |\n| 1Password | `onepassword` | Cloud | ✅ |\n| Keeper Secrets Manager | `keeper` | Cloud | ✅ |\n| Doppler | `doppler` | Cloud | ✅ |\n| CyberArk Conjur | `cyberark` | Self-hosted/Cloud | Coming soon |\n| Akeyless Vault | `akeyless` | Cloud | Coming soon |\n\n\u003e 🔌 **Looking for a different provider?** We're constantly expanding our support for secrets management systems. Open an issue in our [GitHub repository](https://github.com/bytehide/dotsecrets) describing the provider you need, or submit a pull request implementing a new provider by following our [contribution guidelines](./CONTRIBUTING.md).\n\n### Provider Configuration\n\nEach provider has specific configuration requirements. The easiest way to configure a provider is using the setup command:\n\n```bash\nnpx dotsecrets setup\n```\n\nAlternatively, you can configure providers manually by setting the appropriate environment variables:\n\n#### Environment Variables (Default)\n\nNo configuration needed - works out of the box.\n\n#### ByteHide Secrets\n\n```bash\nDOTSECRETS_PLUGIN=bytehide\nBYTEHIDE_SECRETS_TOKEN=your-token\nBYTEHIDE_SECRETS_ENVIRONMENT=production\n```\n\n#### AWS Secrets Manager\n\n```bash\nDOTSECRETS_PLUGIN=aws\nAWS_REGION=us-east-1\nAWS_ACCESS_KEY_ID=your-access-key\nAWS_SECRET_ACCESS_KEY=your-secret-key\n```\n\n#### Azure Key Vault\n\n```bash\nDOTSECRETS_PLUGIN=azure\nAZURE_KEYVAULT_URI=https://your-vault.vault.azure.net\nAZURE_CLIENT_ID=your-client-id\nAZURE_TENANT_ID=your-tenant-id\nAZURE_CLIENT_SECRET=your-client-secret\n```\n\n#### Google Cloud Secret Manager\n\n```bash\nDOTSECRETS_PLUGIN=gcp\nGOOGLE_APPLICATION_CREDENTIALS=/path/to/credentials.json\n# Or use credential object directly\nGOOGLE_CREDENTIALS={\"type\":\"service_account\",...}\n```\n\n#### HashiCorp Vault\n\nSelf-hosted option:\n\n```bash\nDOTSECRETS_PLUGIN=hashicorp\nVAULT_ADDR=https://your-vault-instance:8200\nVAULT_TOKEN=your-vault-token\n```\n\nHCP Cloud option:\n\n```bash\nDOTSECRETS_PLUGIN=hashicorp\nHCP_CLIENT_ID=your-client-id\nHCP_CLIENT_SECRET=your-client-secret\nHCP_ORG_ID=your-org-id\nHCP_PROJECT_ID=your-project-id\nHCP_APP_NAME=your-app-name\n```\n\n#### IBM Cloud Secrets Manager\n\n```bash\nDOTSECRETS_PLUGIN=ibm\nIBM_CLOUD_API_KEY=your-api-key\nIBM_SECRETS_MANAGER_URL=your-instance-url\n```\n\n#### 1Password\n\n```bash\nDOTSECRETS_PLUGIN=onepassword\nOP_CONNECT_HOST=your-connect-server-url\nOP_CONNECT_TOKEN=your-connect-token\nOP_VAULT=your-vault-name\n```\n\n#### Keeper Secrets Manager\n\n```bash\nDOTSECRETS_PLUGIN=keeper\nKEEPER_CONFIG_FILE=/path/to/your/config.json\nKEEPER_FOLDER_UID=your-folder-uid\n```\n\n#### Doppler\n\n```bash\nDOTSECRETS_PLUGIN=doppler\nDOPPLER_TOKEN=your-doppler-token\nDOPPLER_PROJECT=your-project-name\nDOPPLER_CONFIG=your-config-name\n```\n\n### Provider Selection Logic\n\nDotSecrets determines which provider to use in the following order:\n\n1. `DOTSECRETS_PLUGIN` environment variable\n2. Configuration in `dotsecrets.config.json`\n3. Defaults to environment variables if no provider is specified\n\n### Performance Optimization\n\nDotSecrets includes built-in performance optimizations for production environments:\n\n- **Automatic caching**: Secrets retrieved from external providers are automatically cached in memory to minimize API calls.\n- **Batch loading**: When possible, DotSecrets retrieves multiple secrets in a single network request.\n- **Parallel requests**: For providers that don't support batch loading, DotSecrets uses concurrent requests with rate limiting.\n\nThis ensures high performance in production environments while maintaining minimal network overhead, even when accessing dozens or hundreds of secrets.\n\n### Development vs. Production Workflow\n\nTypical workflow between environments:\n\n```javascript\n// Development: Uses local .env and .secrets files\n// No special configuration needed\n\n// Production: Set the provider via environment variables\n// DOTSECRETS_PLUGIN=bytehide\n// BYTEHIDE_SECRETS_TOKEN=your-bytehide-token\n\n// Your code stays EXACTLY THE SAME\nasync function getDatabase() {\n  // Works with ANY provider\n  const connectionString = await secrets.DATABASE_URL.required();\n  return createConnection(connectionString);\n}\n```\n\n## 6. 🛠️ Common Usage Patterns\n\nDotSecrets provides numerous validation and transformation methods to ensure your secrets meet your requirements.\n\n### Basic Validation\n\n```javascript\n// Ensure a secret exists\nconst apiKey = await secrets.API_KEY.required();\n\n// Check that a secret is not empty\nconst username = await secrets.USERNAME.notEmpty();\n\n// Trim whitespace\nconst email = await secrets.EMAIL.trim();\n\n// String length validation\nconst password = await secrets.PASSWORD.lengthBetween(8, 100);\n```\n\n### Type Conversion\n\n```javascript\n// Convert to number\nconst port = await secrets.PORT.number();\n\n// Convert to boolean (true for: \"true\", \"yes\", \"1\", \"on\")\nconst debugMode = await secrets.DEBUG_MODE.boolean();\n\n// Parse JSON with type safety\nconst config = await secrets.CONFIG.json();\nconst serverSettings = await secrets.SETTINGS.json();\n```\n\n### Default Values\n\nWhen a secret might not exist, you can provide defaults:\n\n```javascript\n// Use default if secret doesn't exist\nconst timeout = await secrets.TIMEOUT.default(\"5000\");\n\n// With type conversion\nconst maxRetries = await secrets.MAX_RETRIES.number().default(3);\nconst isFeatureEnabled = await secrets.FEATURE_ENABLED.boolean().default(false);\n```\n\n### Complex Validation Chains\n\nChain multiple validations together for complex requirements:\n\n```javascript\n// Number validation chain\nconst serverPort = await secrets.PORT\n  .number()        // Convert to number\n  .required()      // Must exist\n  .min(1024)       // Must be \u003e= 1024\n  .max(65535);     // Must be \u003c= 65535\n\n// String validation chain\nconst emailAddress = await secrets.EMAIL\n  .trim()                              // Remove whitespace\n  .required()                          // Must exist\n  .regex(/^[\\w.-]+@[\\w.-]+\\.\\w+$/);   // Must match pattern\n\n// Boolean with validation\nconst featureFlag = await secrets.FEATURE_FLAG\n  .boolean()      // Convert to boolean\n  .required()     // Must exist\n  .true();        // Must be true\n```\n\n### Transformations\n\nApply transformations to secret values:\n\n```javascript\n// Case transformations\nconst countryCode = await secrets.COUNTRY_CODE.toUpperCase();\nconst username = await secrets.USERNAME.toLowerCase();\n\n// JSON transformation with validation\nconst config = await secrets.CONFIG\n  .json()\n  .required();\n```\n\n### Error Handling\n\nHandle validation errors gracefully:\n\n```javascript\ntry {\n  const apiKey = await secrets.API_KEY.required();\n  // Use apiKey...\n} catch (error) {\n  // Handle specific validation error\n  console.error(\"API key missing:\", error.message);\n  // Fallback or exit gracefully\n}\n```\n\n### Using in Express.js Middleware\n\nCreate middleware to ensure required secrets exist:\n\n```javascript\nfunction requireSecrets(...secretKeys) {\n  return async (req, res, next) =\u003e {\n    try {\n      for (const key of secretKeys) {\n        // This will throw if any secret is missing\n        await secrets[key].required();\n      }\n      next();\n    } catch (error) {\n      res.status(500).json({\n        error: `Missing required secret: ${error.message}`\n      });\n    }\n  };\n}\n\n// Use middleware on routes that need specific secrets\napp.get('/api/data', \n  requireSecrets('API_KEY', 'DATABASE_URL'), \n  (req, res) =\u003e {\n    // All required secrets exist\n    // Your route handler...\n  }\n);\n```\n\n## 7. ⚙️ Configuration\n\nDotSecrets is designed to work with zero configuration, but offers extensive customization options when needed.\n\n### Configuration File (Recommended)\n\nThe recommended way to configure DotSecrets is through a JSON configuration file. Create a file named `dotsecrets.config.json` in your project root:\n\n```json\n{\n  \"path\": \".secrets\",\n  \"envPath\": \".env\",\n  \"environment\": \"development\",\n  \"watch\": true,\n  \"expand\": true,\n  \"debug\": false,\n  \"override\": false\n}\n```\n\nDotSecrets will automatically discover and load this file. Alternatively, you can place it in:\n\n- `.dotsecrets.config.json`\n- `config/dotsecrets.config.json`\n\n### Configuration Priority\n\nDotSecrets loads configuration from multiple sources, with the following priority (highest to lowest):\n\n1. Explicit parameters in code: `config({ watch: true })`\n2. Environment variables: `DOTSECRETS_WATCH=true`\n3. Configuration file: `dotsecrets.config.json`\n4. Default values\n\n### Available Options\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `path` | string | `.secrets` | Path to the secrets file |\n| `envPath` | string | `.env` | Path to the environment file |\n| `environment` | string | `process.env.NODE_ENV` | Environment name for loading specific files |\n| `encoding` | string | `utf8` | File encoding for reading config files |\n| `watch` | boolean | `true` in development | Watch files for changes and reload |\n| `debug` | boolean | `false` | Enable debug logging |\n| `override` | boolean | `false` | Override existing environment variables |\n| `expand` | boolean | `false` | Expand variable references like `${VAR}` |\n| `encryptionKey` | string | `process.env.DOTSECRETS_ENCRYPTION_KEY` | Key for decrypting encrypted secrets |\n| `autoInit` | boolean | `true` | Automatically initialize on import |\n| `skipAutoConfig` | boolean | `false` | Skip automatic configuration |\n\n### Environment Variables\n\nAll options can also be set using environment variables:\n\n```bash\n# Configuration via environment variables\nDOTSECRETS_PATH=./config/.secrets\nDOTSECRETS_ENV_PATH=./config/.env\nDOTSECRETS_ENVIRONMENT=staging\nDOTSECRETS_WATCH=true\nDOTSECRETS_DEBUG=true\nDOTSECRETS_OVERRIDE=false\nDOTSECRETS_EXPAND=true\nDOTSECRETS_ENCRYPTION_KEY=your-encryption-key\nDOTSECRETS_AUTO_INIT=true\nDOTSECRETS_SKIP_AUTO_CONFIG=false\nDOTSECRETS_PLUGIN=aws\n```\n\n### Programmatic Configuration\n\nFor advanced use cases, you can configure DotSecrets programmatically:\n\n```javascript\nimport { config } from 'dotsecrets';\n\n// Override configuration programmatically\nconst loadedSecrets = config({\n  path: './config/secrets/.secrets',\n  environment: 'staging',\n  watch: true,\n  expand: true,\n  debug: process.env.DEBUG === 'true'\n});\n\nconsole.log(`Loaded ${Object.keys(loadedSecrets).length} secrets`);\n```\n\n### File Watching and Reload Hooks\n\nDotSecrets can automatically reload secrets when configuration files change and execute custom scripts:\n\n```javascript\n// Enable file watching (default in development)\nconfig({ watch: true });\n```\n\nWhen a watched file changes, DotSecrets will:\n\n1. Reload all secrets automatically\n2. Execute reload hooks in the following order:\n\n#### Custom Reload Hooks\n\nDefine a script in your `package.json`:\n\n```json\n{\n  \"scripts\": {\n    \"onSecretsUpdate\": \"node scripts/reload-app.js\"\n  }\n}\n```\n\nOr create a standalone script file in your project root:\n\n- `dotSecretsUpdate.js`\n- `dotSecretsUpdate.ts`\n\nThese scripts will be executed whenever your secrets change, allowing you to:\n\n- Restart server components\n- Clear caches\n- Notify systems of configuration changes\n- Update connected clients\n\n### Custom Configuration Example\n\nHere's a complete example with custom configuration:\n\n```javascript\n// In your application entry point\nimport { config } from 'dotsecrets';\n\n// Load configuration with custom settings\nconfig({\n  // Custom file paths\n  path: './config/secrets/.secrets',\n  envPath: './config/env/.env',\n  \n  // Use production environment explicitly\n  environment: 'production',\n  \n  // Enable variable expansion\n  expand: true,\n  \n  // Enable file watching in development\n  watch: process.env.NODE_ENV !== 'production',\n  \n  // Enable debugging in development\n  debug: process.env.NODE_ENV !== 'production',\n  \n  // Use encryption key from environment\n  encryptionKey: process.env.SECRET_KEY\n});\n```\n\nFor most applications, the zero-configuration approach is sufficient, with DotSecrets automatically loading configuration from files and environment variables.\n\n## 8. 🛠️ CLI Tools\n\nDotSecrets includes several command-line tools to simplify setup, migration, and integration with your development environment.\n\n### Setup Command\n\nThe `setup` command helps you initialize and configure DotSecrets in your project:\n\n```bash\nnpx dotsecrets setup\n```\n\nThis interactive wizard:\n\n1. Creates necessary configuration files (`.secrets`, `.env`, `.public`) if they don't exist\n2. Updates your `.gitignore` to exclude sensitive files\n3. Guides you through configuring a secrets provider (ByteHide, AWS, Azure, etc.)\n4. Sets up required environment variables for your chosen provider\n\nOptions:\n\n- `--path \u003cfolder\u003e` - Specify a folder path (default: current directory)\n\n### Push Command\n\nThe `push` command enables you to securely transfer your local secrets to any supported production provider:\n\n```bash\nnpx dotsecrets push\n```\n\nThis interactive tool:\n\n1. Scans your project for `.secrets` and `.env` files\n2. Allows you to select which file contains the secrets to push\n3. Lets you choose specific secrets to include or exclude\n4. Presents a list of available secrets providers (AWS, Azure, ByteHide, etc.)\n5. Securely uploads your selected secrets to the chosen provider\n\nThis command provides a secure bridge between development and production environments without ever exposing secrets in version control, making it easy to maintain consistent configurations across all environments.\n\nOptions:\n\n- `--path \u003cfolder\u003e` - Specify a folder path to scan (default: current directory)\n\n### Migrate Command\n\nThe `migrate` command helps you transition from dotenv to DotSecrets:\n\n```bash\nnpx dotsecrets migrate\n```\n\nThis comprehensive migration tool:\n\n1. Scans for existing `.env` files and converts them to `.secrets` equivalents\n2. Transforms `process.env.X` references in your code to `secrets.X`\n3. Removes dotenv configuration code from your project\n4. Optionally uninstalls the dotenv package\n\nOptions:\n\n- `--path \u003cfolder\u003e` - Specify a folder path to scan (default: current directory)\n\n### Sync IDE Command\n\nThe `sync-ide` command generates TypeScript definitions for IDE autocompletion:\n\n```bash\nnpx dotsecrets sync-ide\n```\n\nThis tool:\n\n1. Scans your project for all available secrets\n2. Generates TypeScript definition files for enhanced IDE experience\n3. Creates complete type definitions for the `secrets` object and all validation methods\n4. Supports both TypeScript and JavaScript files with JSDoc annotations\n\nOptions:\n\n- `--outDir \u003cdir\u003e` - Directory to output type definitions (default: \"types\")\n- `--fileName \u003cname\u003e` - Name of the generated definition file (default: \"dotsecrets.d.ts\")\n- `--verbose` - Show verbose output during generation\n\n## 9. 🔬 Advanced Usage\n\n### Creating Custom Providers\n\nThe recommended way to add support for a new secrets provider is to contribute directly to the DotSecrets project by submitting a Pull Request. Please refer to our [CONTRIBUTING.md](./CONTRIBUTING.md) guide for detailed instructions on implementing a new provider.\n\nFor a quick overview, here's how to create a custom provider:\n\n```typescript\nimport { BaseSecretsPlugin, ISecretsPlugin } from 'dotsecrets/plugins';\n\nexport class MyCustomProvider extends BaseSecretsPlugin implements ISecretsPlugin {\n  pluginName = \"My Custom Provider\";\n  \n  async getSecret(secretKey: string): Promise\u003cstring | undefined\u003e {\n    // Your implementation\n    const parsedKey = this.parseSecretName(secretKey);\n    return await yourSecretsFetcher(parsedKey);\n  }\n  \n  // Implement other required methods\n}\n\n// Register your provider\nimport { autoInitSecretsPlugin } from 'dotsecrets';\nautoInitSecretsPlugin({ plugin: new MyCustomProvider(), priority: 10 });\n```\n\nSee the [CONTRIBUTING.md](./CONTRIBUTING.md) file for the complete guide on implementing providers, including best practices, testing requirements, and documentation.\n\n### Custom Validators\n\nYou can extend the validation capabilities with your own custom validators by extending the `SecretValue` class:\n\n```typescript\nimport { SecretValue } from 'dotsecrets';\n\n// Extend the SecretValue prototype to add custom validators\ndeclare module 'dotsecrets' {\n  interface SecretValue {\n    // Add declaration for your custom method\n    isValidEmail(): SecretValue;\n  }\n}\n\n// Add custom validator implementation\nSecretValue.prototype.isValidEmail = function(this: SecretValue): SecretValue {\n  const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n  return this.regex(emailRegex, \"Invalid email format\");\n};\n\n// Now you can use your custom validator\nconst email = await secrets.USER_EMAIL.isValidEmail();\n```\n\n### Integration with Frameworks\n\n#### Express.js Middleware\n\nCreate middleware to ensure required secrets exist:\n\n```javascript\nimport { secrets } from 'dotsecrets';\n\nfunction requireSecrets(...secretKeys) {\n  return async (req, res, next) =\u003e {\n    try {\n      for (const key of secretKeys) {\n        // This will throw if any secret is missing\n        await secrets[key].required();\n      }\n      next();\n    } catch (error) {\n      res.status(500).json({\n        error: `Missing required secret: ${error.message}`\n      });\n    }\n  };\n}\n\n// Use middleware on routes that need specific secrets\napp.get('/api/data', \n  requireSecrets('API_KEY', 'DATABASE_URL'), \n  (req, res) =\u003e {\n    // All required secrets exist\n    // Your route handler...\n  }\n);\n```\n\n#### Next.js Integration\n\nFor Next.js applications, be careful to only initialize DotSecrets on the server side:\n\n```javascript\n// app/layout.js or pages/_app.js (server-side initialization)\nimport { preloadAllSecrets } from 'dotsecrets';\n\n// Only initialize on the server, not in the browser\nif (typeof window === 'undefined') {\n  // This runs only on the server side\n  preloadAllSecrets();\n}\n\nexport default function RootLayout({ children }) {\n  return \u003chtml lang=\"en\"\u003e{children}\u003c/html\u003e;\n}\n```\n\nIn your server components or API routes, you can use `await` directly:\n\n```javascript\n// Server component\nimport { secrets } from 'dotsecrets';\n\nexport default async function AdminPage() {\n  const apiKey = await secrets.API_KEY.required();\n  // Use the apiKey...\n  return \u003cdiv\u003eAdmin features\u003c/div\u003e;\n}\n```\n\nFor client-side components, only use `PUBLIC_` prefixed secrets from the `.public` file:\n\n```javascript\n// Client component\n'use client';\nimport { secrets } from 'dotsecrets';\n\nexport default function ClientComponent() {\n  // Only PUBLIC_ values can be used on the client side\n  const apiVersion = secrets.PUBLIC_API_VERSION;\n  const featureFlags = secrets.PUBLIC_FEATURE_FLAGS.json();\n  \n  return \u003cdiv\u003eUsing API v{apiVersion}\u003c/div\u003e;\n}\n```\n\n### Testing with DotSecrets\n\nFor testing environments, you can mock secrets or provide test-specific values:\n\n#### Using Environment Files for Tests\n\nCreate a `.secrets.test` file with test-specific values:\n\n```bash\n# .secrets.test\nDATABASE_URL=postgresql://test:test@localhost:5432/testdb\nAPI_KEY=test-api-key\n```\n\nThen configure your test runner to set `NODE_ENV=test` to automatically load these files.\n\n#### Mocking Secrets in Tests\n\nFor unit tests, you can mock the entire secrets module:\n\n```javascript\n// __mocks__/dotsecrets.js\nconst mockSecrets = {\n  API_KEY: { \n    required: () =\u003e Promise.resolve('test-api-key'),\n    valueOf: () =\u003e 'test-api-key',\n    toString: () =\u003e 'test-api-key'\n  },\n  DATABASE_URL: {\n    required: () =\u003e Promise.resolve('mock-db-url'),\n    valueOf: () =\u003e 'mock-db-url',\n    toString: () =\u003e 'mock-db-url'\n  }\n};\n\nexport const secrets = new Proxy({}, {\n  get: (target, prop) =\u003e {\n    if (mockSecrets[prop]) return mockSecrets[prop];\n    return {\n      required: () =\u003e Promise.resolve(`mock-${prop}`),\n      valueOf: () =\u003e `mock-${prop}`,\n      toString: () =\u003e `mock-${prop}`\n    };\n  }\n});\n\nexport const preloadAllSecrets = async () =\u003e Promise.resolve(true);\n```\n\nThen in your Jest configuration:\n\n```javascript\n// jest.config.js\nmodule.exports = {\n  // ...\n  moduleNameMapper: {\n    '^dotsecrets$': '\u003crootDir\u003e/__mocks__/dotsecrets.js',\n  },\n};\n```\n\n#### Integration Tests\n\nFor integration tests that need to access real configurations:\n\n```javascript\nimport { config, preloadAllSecrets, secrets } from 'dotsecrets';\n\nbeforeAll(async () =\u003e {\n  // Set up test-specific configuration\n  config({\n    path: '.secrets.test',\n    environment: 'test',\n    expand: true\n  });\n  \n  // Preload secrets for synchronous access in tests\n  await preloadAllSecrets();\n});\n\ntest('database connection works', async () =\u003e {\n  const dbUrl = await secrets.DATABASE_URL.required();\n  // Test database connection with the URL\n  expect(dbUrl).toContain('testdb');\n});\n```\n\nBy using these patterns, you can ensure your tests run with consistent, isolated configurations without affecting your development or production environments.\n\n## 10. ❓ FAQ \u0026 Troubleshooting\n\n### Common Issues\n\n#### Secrets not loading in production\n\n**Problem**: Secrets are available in development but not in production.\n\n**Solution**:\n\n- Verify your provider configuration is correct\n- Check environment variables for the chosen provider\n- Enable debug mode with `DOTSECRETS_DEBUG=true` to see detailed logs\n- Confirm that the secret keys are correctly formatted for your provider\n\n```javascript\n// Enable debug mode to troubleshoot\nconfig({ debug: true });\n```\n\n#### TypeError: secrets.X is not a function\n\n**Problem**: Getting error when trying to access a secret.\n\n**Solution**: This usually happens when using synchronous access without preloading.\n\n```javascript\n// ❌ Incorrect usage without preloading\nconst apiKey = secrets.API_KEY.required(); // TypeError\n\n// ✅ Correct async usage\nconst apiKey = await secrets.API_KEY.required();\n\n// ✅ Correct sync usage (after preloading)\nawait preloadAllSecrets();\nconst apiKey = secrets.API_KEY.required();\n```\n\n#### Validation errors not showing expected messages\n\n**Problem**: Error messages from validation are unclear or not showing.\n\n**Solution**: Wrap secret access in try/catch blocks to handle validation errors properly.\n\n```javascript\ntry {\n  const port = await secrets.PORT.number().between(1000, 65535);\n} catch (error) {\n  console.error('Validation failed:', error.message);\n  // Provide fallback or exit gracefully\n}\n```\n\n#### Secrets not updating after file changes\n\n**Problem**: Changes to `.env` or `.secrets` files are not reflected in the application.\n\n**Solution**: Make sure file watching is enabled and your reload hooks are working.\n\n```javascript\n// Enable file watching explicitly\nconfig({ watch: true });\n\n// Add a script in package.json\n// \"scripts\": {\n//   \"onSecretsUpdate\": \"node ./scripts/reload-app.js\"\n// }\n```\n\n### Performance Considerations\n\n#### Optimize secret loading\n\n- **Secret Caching**: DotSecrets automatically caches secrets after their first retrieval. Once you've used `await secrets.SECRET_NAME` once, subsequent accesses to the same secret will use the cached value without making additional provider API calls.\n- **Use preloading** for initial loading: `preloadAllSecrets()` is useful to load all secrets at startup, but remember that individual secrets are already cached after their first access.\n- **Transformations are not cached**: Each call to transformers like `.number()` or `.boolean()` is executed again, so store the result rather than calling the transformation repeatedly.\n\n```javascript\n// Efficient pattern - secrets are automatically cached after first retrieval\nconst apiKey = await secrets.API_KEY; // First access fetches from provider\nconst sameApiKey = await secrets.API_KEY; // Uses cached value\n\n// For transformed values, store the result\nconst port = await secrets.PORT.number(); // Store the transformed value\n// Later use port directly instead of secrets.PORT.number() again\n```\n\n#### Reduce network overhead\n\n- **Group related secrets** under a single key as JSON to minimize API calls\n- **Consider local caching** for high-traffic applications\n\n```javascript\n// Instead of many individual secrets\n// db_host, db_user, db_password, db_port, db_name\n\n// Use a single JSON configuration\n// DB_CONFIG={\"host\":\"localhost\",\"user\":\"admin\",\"password\":\"secret\",\"port\":5432,\"name\":\"mydb\"}\nconst dbConfig = await secrets.DB_CONFIG.json();\n```\n\n#### Minimize validation chains\n\n- **Create custom validators** for frequently used validation patterns\n- **Use appropriate validators** based on your needs\n\n```javascript\n// Custom validator for common patterns\nSecretValue.prototype.isValidPort = function() {\n  return this.number().between(1024, 65535);\n};\n\n// Now use the custom validator\nconst port = await secrets.PORT.isValidPort();\n```\n\n### Security Best Practices\n\n#### Protect sensitive files\n\n- **Always** add `.secrets` and `.env` to your `.gitignore`\n- Use the `.public` file for non-sensitive values\n- Consider encrypting `.secrets` files for additional security\n\n```bash\n# Set encryption key\nexport DOTSECRETS_ENCRYPTION_KEY=your-secure-key\n```\n\n#### Limit access to secrets\n\n- Use environment-specific files for different deployment environments\n- Apply the principle of least privilege for cloud provider IAM roles\n- Regularly rotate sensitive credentials\n\n```\n.secrets.development # Development-only secrets\n.secrets.staging     # Staging-only secrets\n.secrets.production  # Production-only secrets\n```\n\n#### Secure secret transmission\n\n- Never log or display full secret values\n- Use HTTPS/TLS for all API calls to secrets providers\n- Consider using a VPC or private network for cloud provider APIs\n\n```javascript\n// ❌ Don't log full secrets\nconsole.log(`Using API key: ${apiKey}`); // Security risk\n\n// ✅ Log only references or masked values\nconsole.log(\"API key loaded successfully\"); // Safe\n```\n\n#### Audit and monitoring\n\n- Enable audit logs for cloud provider secret access\n- Monitor for unusual access patterns\n- Implement alerting for suspicious activities\n\n## 11. 📚 API Reference\n\n### Key Functions and Classes\n\n#### `secrets` object\n\nThe main entry point for accessing secrets, supporting both synchronous and asynchronous access patterns.\n\n```javascript\nimport { secrets } from 'dotsecrets';\n\n// Asynchronous access (recommended)\nconst apiKey = await secrets.API_KEY;\n\n// Synchronous access (after preloading)\nconst port = secrets.PORT;\n```\n\n#### `config(options)`\n\nConfigures the library with the specified options and loads secrets from all sources.\n\n```javascript\nimport { config } from 'dotsecrets';\n\n// Configure with custom options\nconst loadedSecrets = config({\n  path: '.custom-secrets',\n  environment: 'staging',\n  watch: true\n});\n```\n\nReturns a `Record\u003cstring, string\u003e` of loaded secrets.\n\n#### `preloadAllSecrets()`\n\nPreloads all secrets for synchronous access.\n\n```javascript\nimport { preloadAllSecrets, secrets } from 'dotsecrets';\n\n// At application startup\nawait preloadAllSecrets();\n\n// Later in synchronous code\nfunction getApiClient() {\n  return new ApiClient(secrets.API_KEY);\n}\n```\n\nReturns a `Promise\u003cvoid\u003e` that resolves when all secrets are preloaded.\n\n#### `preloadSecrets(keys)`\n\nPreloads specific secrets for synchronous access.\n\n```javascript\nimport { preloadSecrets, secrets } from 'dotsecrets';\n\n// Preload only specific secrets\nawait preloadSecrets(['API_KEY', 'DATABASE_URL']);\n\n// Now use them synchronously\nconst apiClient = new ApiClient(secrets.API_KEY);\n```\n\nReturns a `Promise\u003cvoid\u003e` that resolves when the specified secrets are preloaded.\n\n#### `autoInitSecretsPlugin(options)`\n\nRegisters a custom secrets plugin with the specified options.\n\n```javascript\nimport { autoInitSecretsPlugin } from 'dotsecrets';\nimport { MyCustomProvider } from './MyCustomProvider';\n\n// Register custom provider\nautoInitSecretsPlugin({\n  plugin: new MyCustomProvider(),\n  priority: 10 // Higher number = higher priority\n});\n```\n\n#### `SecretValue` class\n\nA chainable wrapper for string secret values with validation and transformation methods.\n\n```javascript\n// String validation methods\nawait secrets.EMAIL.required();\nawait secrets.USERNAME.notEmpty();\nawait secrets.PASSWORD.lengthBetween(8, 20);\nawait secrets.API_KEY.regex(/^[a-z0-9]{32}$/);\n\n// Transformations\nawait secrets.URL.trim();\nawait secrets.CODE.toLowerCase();\nawait secrets.COUNTRY.toUpperCase();\n\n// Type conversions\nawait secrets.PORT.number();\nawait secrets.DEBUG.boolean();\nawait secrets.CONFIG.json();\n```\n\n#### `NumberSecretValue` class\n\nSpecialized validation for numeric values.\n\n```javascript\n// Number validation\nawait secrets.PORT.number().min(1024);\nawait secrets.TIMEOUT.number().max(30000);\nawait secrets.RETRY_COUNT.number().between(1, 5);\nawait secrets.USER_COUNT.number().positive();\nawait secrets.TEMPERATURE.number().negative();\nawait secrets.PAGE_SIZE.number().integer();\n```\n\n#### `BooleanSecretValue` class\n\nSpecialized validation for boolean values.\n\n```javascript\n// Boolean validation\nawait secrets.FEATURE_ENABLED.boolean().required();\nawait secrets.DEBUG_MODE.boolean().true();\nawait secrets.MAINTENANCE_MODE.boolean().false();\n```\n\n#### `JsonSecretValue` class\n\nSpecialized validation for JSON values.\n\n```javascript\n// JSON validation and access\nconst config = await secrets.SERVER_CONFIG.json();\nconst features = await secrets.FEATURE_FLAGS.json();\n```\n\n### Options Documentation\n\n#### `DotSecretsOptions` interface\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `path` | string | `.secrets` | Path to the secrets file |\n| `envPath` | string | `.env` | Path to the environment file |\n| `environment` | string | `process.env.NODE_ENV` | Environment name for loading specific files |\n| `encoding` | BufferEncoding | `utf8` | File encoding for reading config files |\n| `watch` | boolean | `true` in development | Watch files for changes and reload |\n| `debug` | boolean | `false` | Enable debug logging |\n| `override` | boolean | `false` | Override existing environment variables |\n| `expand` | boolean | `false` | Expand variable references like `${VAR}` |\n| `encryptionKey` | string | `process.env.DOTSECRETS_ENCRYPTION_KEY` | Key for decrypting encrypted secrets |\n| `autoInit` | boolean | `true` | Automatically initialize on import |\n| `skipAutoConfig` | boolean | `false` | Skip automatic configuration |\n\n#### `AutoInitOptions` interface\n\n| Option | Type | Description |\n|--------|------|-------------|\n| `plugin` | `ISecretsPlugin` | The plugin instance to register |\n| `priority` | number | Priority level for resolution (higher = higher priority) |\n| `condition` | () =\u003e boolean | Optional function to determine if this plugin should be used |\n\n#### All Environment Variables\n\n| Variable | Description |\n|----------|-------------|\n| `DOTSECRETS_PATH` | Path to the secrets file |\n| `DOTSECRETS_ENV_PATH` | Path to the environment file |\n| `DOTSECRETS_ENVIRONMENT` | Environment name for loading specific files |\n| `DOTSECRETS_ENCODING` | File encoding for reading config files |\n| `DOTSECRETS_WATCH` | Watch files for changes and reload |\n| `DOTSECRETS_DEBUG` | Enable debug logging |\n| `DOTSECRETS_OVERRIDE` | Override existing environment variables |\n| `DOTSECRETS_EXPAND` | Expand variable references like `${VAR}` |\n| `DOTSECRETS_ENCRYPTION_KEY` | Key for decrypting encrypted secrets |\n| `DOTSECRETS_AUTO_INIT` | Automatically initialize on import |\n| `DOTSECRETS_SKIP_AUTO_CONFIG` | Skip automatic configuration |\n| `DOTSECRETS_PLUGIN` | ID of the plugin to use for loading secrets |\n\n## 12. 💪 Contributing \u0026 Community\n\nWe believe that great tools are built together. DotSecrets is an open-source project that welcomes contributions from developers of all experience levels.\n\n### How to Contribute\n\nWhether you're fixing a bug, adding a feature, or improving documentation, your contributions make DotSecrets better for everyone.\n\n1. Check out our [CONTRIBUTING.md](./CONTRIBUTING.md) guide for detailed instructions\n2. Fork the repository and create your branch from `main`\n3. Make your changes and ensure tests pass\n4. Submit a pull request with a clear description of your improvements\n\n### Code of Conduct\n\nWe're committed to fostering an open and welcoming community. Please read our [Code of Conduct](./CODE_OF_CONDUCT.md) to understand the behavior we expect from all participants.\n\n### Security Disclosures\n\nDotSecrets takes security seriously. If you discover a vulnerability or security issue:\n\n- **Do not** create a public GitHub issue\n- Report it confidentially to [support@bytehide.com](mailto:support@bytehide.com)\n- Include detailed information about the vulnerability\n- Allow time for the issue to be addressed before public disclosure\n\nWe appreciate your help in keeping DotSecrets and its users safe.\n\n### License\n\nDotSecrets is available under the [BSD 2-Clause License](./LICENSE). This permissive license allows you to use, modify, and distribute the code in both commercial and non-commercial applications, with minimal restrictions.\n\n## 🚀 From ByteHide with 💙\n\nDotSecrets was created by the team at [ByteHide](https://www.bytehide.com) with a simple mission: to simplify the lives of developers while enhancing security.\n\nWe built this tool because we believe that security shouldn't come at the cost of developer experience. Managing secrets should be straightforward, standardized, and accessible to everyone—from solo developers to enterprise teams.\n\nDotSecrets represents our commitment to democratizing security practices. We want to empower you to build with confidence, knowing your sensitive information is handled properly without adding complexity to your workflow.\n\nWe're excited to see what you build with DotSecrets, and we hope you'll join our community in making secret management simple, secure, and standardized across the JavaScript ecosystem.\n\nWhether you're using DotSecrets in a weekend project or an enterprise application, we'd love to hear from you! Share your feedback, stories, or just say hello at [@byte_hide](https://x.com/byte_hide).\n\n---\n\nBuilt with passion by the ByteHide team and the open-source community. Happy coding! 🎉\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbytehide%2Fdotsecrets","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbytehide%2Fdotsecrets","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbytehide%2Fdotsecrets/lists"}