Plain Text
Store secrets as plain text (for default values only!).
Usage
Plain text is the default when no provider is specified:
toml
[secrets.NODE_ENV]
default = "development" # ← Plain text, safe for non-sensitive defaults
[secrets.LOG_LEVEL]
default = "info" # ← Plain text
[secrets.API_TIMEOUT]
default = "30" # ← Plain textWhen Plain Text is Appropriate
1. Non-Sensitive Defaults
toml
[secrets.PORT]
default = "3000"
[secrets.HOST]
default = "localhost"
[secrets.NODE_ENV]
default = "development"
[secrets.LOG_LEVEL]
default = "info"2. Public Configuration
toml
[secrets.PUBLIC_API_URL]
default = "https://api.example.com"
[secrets.CDN_URL]
default = "https://cdn.example.com"3. Development Fallbacks
toml
[secrets.DATABASE_URL]
provider = "age"
value = "encrypted-production-db..."
default = "postgresql://localhost/dev_db" # ← Fallback for local devIf the encrypted value can't be decrypted (e.g., missing key), falls back to the plaintext default.
❌ When NOT to Use Plain Text
Never for Passwords
toml
# ❌ BAD - Never do this!
[secrets.DATABASE_PASSWORD]
default = "super-secret-password"
# ✅ GOOD - Use encryption
[secrets.DATABASE_PASSWORD]
provider = "age"
value = "encrypted..."Never for API Keys
toml
# ❌ BAD
[secrets.STRIPE_KEY]
default = "sk_live_abc123xyz789"
# ✅ GOOD
[secrets.STRIPE_KEY]
provider = "age"
value = "encrypted..."Never for Tokens
toml
# ❌ BAD
[secrets.JWT_SECRET]
default = "my-secret-key"
# ✅ GOOD
[secrets.JWT_SECRET]
provider = "age"
value = "encrypted..."Mixing Plain and Encrypted
It's common to mix plain text defaults with encrypted values:
toml
# Encrypted sensitive values
[providers.age]
type = "age"
recipients = ["age1..."]
[secrets.DATABASE_PASSWORD]
provider = "age"
value = "encrypted..."
default = "dev-password" # ← Fallback for local dev (non-production)
# Plain text non-sensitive defaults
[secrets.DATABASE_HOST]
default = "localhost"
[secrets.DATABASE_PORT]
default = "5432"
[secrets.LOG_LEVEL]
default = "info"Security Best Practices
- Never commit sensitive data as plain text
- Use encryption for anything that shouldn't be public
- Use plain text only for truly non-sensitive defaults
- Review
.gitignore- Ensure sensitive files aren't tracked - Use
fnox scanto detect secrets - Scans for accidentally committed secrets
Scan for Secrets
fnox can scan your codebase for accidentally committed secrets:
bash
# Scan for potential secrets
fnox scan
# Scan specific directory
fnox scan src/
# Scan and fix (interactive)
fnox scan --fixExamples
Safe Plain Text Usage
toml
# Application settings (non-sensitive)
[secrets.APP_NAME]
default = "My Application"
[secrets.APP_VERSION]
default = "1.0.0"
[secrets.ENVIRONMENT]
default = "development"
[secrets.DEBUG_MODE]
default = "true"
[secrets.TIMEOUT_MS]
default = "5000"
# Public URLs
[secrets.PUBLIC_SITE_URL]
default = "https://example.com"
[secrets.DOCS_URL]
default = "https://docs.example.com"Mixed Usage (Plain + Encrypted)
toml
[providers.age]
type = "age"
recipients = ["age1..."]
# Sensitive (encrypted)
[secrets.DATABASE_URL]
provider = "age"
value = "encrypted-connection-string..."
[secrets.API_KEY]
provider = "age"
value = "encrypted-key..."
# Non-sensitive (plain)
[secrets.DATABASE_POOL_SIZE]
default = "10"
[secrets.CACHE_TTL_SECONDS]
default = "3600"
[secrets.FEATURE_FLAG_NEW_UI]
default = "false"Remember
- ✅ Plain text is fine for public, non-sensitive configuration
- ✅ Use defaults for fallback values
- ❌ Never use plain text for passwords, keys, or tokens
- ✅ Use age or other providers for sensitive data
- ✅ Run
fnox scanto catch accidental secrets
Next Steps
- Age Encryption - Encrypt sensitive secrets
- Providers Overview - Choose the right provider
- Configuration Reference - Learn more about fnox.toml