Configuration
Hush is configured through a hush.yaml file in your repository root.
Basic Structure
sources: shared: .env development: .env.development production: .env.production
targets: - name: root path: . format: dotenv
- name: app path: ./packages/app format: dotenv include: - EXPO_PUBLIC_*
- name: api path: ./packages/api format: wrangler exclude: - EXPO_PUBLIC_*Sources
The sources section defines your .env files and how they map to environments.
sources: shared: .env # Base variables for all environments development: .env.development # Development-specific overrides production: .env.production # Production-specific overridesSource Merging Order
When decrypting, sources are merged in order with later values overriding earlier ones:
- shared - Base variables
- environment (development or production) - Environment overrides
- .env.local (unencrypted) - Personal overrides (not committed)
Example
# .env (shared)API_URL=https://api.example.comDEBUG=false
# .env.developmentAPI_URL=http://localhost:8787DEBUG=true
# Result for development:# API_URL=http://localhost:8787 (overridden)# DEBUG=true (overridden)Targets
The targets section defines where secrets should be written and in what format.
Required Fields
| Field | Description |
|---|---|
name | Identifier for the target (used in output messages) |
path | Directory where the output file should be written |
format | Output format: dotenv, wrangler, json, or shell |
Optional Fields
| Field | Description |
|---|---|
include | Glob patterns for variables to include |
exclude | Glob patterns for variables to exclude |
Example
targets: - name: app path: ./packages/app format: dotenv include: - EXPO_PUBLIC_* - NEXT_PUBLIC_* - VITE_*Include/Exclude Patterns
Use glob patterns to control which variables reach each target.
Include
Only variables matching any include pattern are written:
targets: - name: client path: ./client format: dotenv include: - EXPO_PUBLIC_* # Variables starting with EXPO_PUBLIC_ - NEXT_PUBLIC_* # Variables starting with NEXT_PUBLIC_Exclude
All variables except those matching exclude patterns are written:
targets: - name: server path: ./server format: wrangler exclude: - EXPO_PUBLIC_* # Exclude client-only variables - NEXT_PUBLIC_*Combined
When both are specified, include is applied first, then exclude:
targets: - name: api path: ./api format: json include: - API_* # Include all API_* variables exclude: - API_DEBUG_* # Except debugging onesOutput Formats
dotenv
Standard .env file format:
DATABASE_URL=postgres://localhost/mydbAPI_KEY=sk_test_xxxOutput file: .env.development or .env.production
wrangler
Cloudflare Wrangler .dev.vars format (same as dotenv, different filename):
DATABASE_URL=postgres://localhost/mydbAPI_KEY=sk_test_xxxOutput file: .dev.vars
json
JSON object format:
{ "DATABASE_URL": "postgres://localhost/mydb", "API_KEY": "sk_test_xxx"}Output file: .env.development.json or .env.production.json
shell
Sourceable shell exports:
#!/bin/shexport DATABASE_URL="postgres://localhost/mydb"export API_KEY="sk_test_xxx"Output file: .env.development.sh or .env.production.sh
Variable Interpolation
Reference other variables using ${VAR} syntax:
HOST=localhostPORT=3000BASE_URL=http://${HOST}:${PORT}API_URL=${BASE_URL}/apiAfter interpolation:
HOST=localhostPORT=3000BASE_URL=http://localhost:3000API_URL=http://localhost:3000/apiSOPS Configuration
Hush uses SOPS for encryption. Configure it in .sops.yaml:
creation_rules: - encrypted_regex: '.*' age: age1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxMultiple Keys
For team environments, use multiple age keys:
creation_rules: - encrypted_regex: '.*' age: >- age1alice..., age1bob..., age1charlie...Anyone with any of these keys can decrypt the secrets.
Complete Example
sources: shared: .env development: .env.development production: .env.production
targets: # Root gets everything for scripts - name: root path: . format: dotenv
# Expo app only gets public variables - name: mobile path: ./packages/mobile format: dotenv include: - EXPO_PUBLIC_*
# Next.js web app gets its public variables - name: web path: ./packages/web format: dotenv include: - NEXT_PUBLIC_*
# API gets everything except public variables - name: api path: ./packages/api format: wrangler exclude: - EXPO_PUBLIC_* - NEXT_PUBLIC_*
# Shared library gets specific variables as JSON - name: shared path: ./packages/shared format: json include: - API_URL - APP_NAME