ConfigShip: A Zero-Dependency, Secure Configuration Manager for Node.js (with Raw Env Support!)
Source: Dev.to
The Problem
I got tired of config management being messy. You’ve got:
- Hard‑coded defaults scattered everywhere
.envfiles that are hard to work with- Different configs for dev / staging / prod
- Runtime overrides that break things
- Prototype‑pollution vulnerabilities (yes, really)
Existing solutions either have too many dependencies, lack features, or are over‑engineered.
My Solution: ConfigShip
Zero dependencies. Seriously – check the package.json yourself.
What Makes It Different?
Layered Resolution (clear priority)
runtime → env → file → defaults
Raw Env Names (NEW in v0.1.2)
config.get("APP_NAME") // Works!
config.get("name") // Also works! (transformed)
Secure by Default
- Protected against prototype pollution
- TypeScript strict mode
- No crashes on missing config
Auto‑Parsing
APP_PORT=3000 # → number 3000
APP_ENABLED=true # → boolean true
APP_DATA={"x":1} # → object {x:1}
Quick Example
import { createConfig } from "config-ship";
const config = createConfig({
defaults: {
db: { host: "localhost", port: 5432 }
},
envPrefix: "APP_",
envFile: ".env"
});
// Access anywhere
config.get("db.host");
config.set("db.port", 5433);
Real‑World Example: Express App
// config/index.js
import { createConfig } from "config-ship";
export const config = createConfig({
defaults: {
server: { port: 3000, host: "localhost" },
db: {
host: "localhost",
port: 5432,
pool: { min: 2, max: 10 }
},
redis: { url: "redis://localhost:6379" },
features: {
rateLimiting: true,
analytics: false
}
},
envPrefix: "MYAPP_",
envFile: ".env", // optional auto‑loading of process.env
rootFile: `config/${process.env.NODE_ENV}.js`
});
// app.js
import express from "express";
import { config } from "./config/index.js";
const app = express();
app.listen(
config.get("server.port"),
() => console.log(`Running on port ${config.get("server.port")}`)
);
Production .env
MYAPP_SERVER__PORT=8080
MYAPP_DB__HOST=prod-db.internal
MYAPP_DB__POOL__MAX=50
MYAPP_REDIS__URL=redis://prod:6379
Notice the __ for nested keys!
Environment Variables Made Easy
Syntax
- Prefix:
APP_(single_separates prefix) - Double
__creates nested paths
APP_DB__HOST=localhost # → db.host
APP_DB__PORT=5432 # → db.port (parsed to number)
APP_FEATURE__BETA=true # → feature.beta (parsed to boolean)
Use Case: Feature Flags
const config = createConfig({
defaults: {
features: {
darkMode: false,
newUI: false,
betaAccess: false
}
},
envPrefix: "FEATURES_"
});
function featureEnabled(name) {
return config.get(`features.${name}`, false);
}
// Usage
if (featureEnabled("darkMode")) {
applyDarkTheme();
}
// Enable for beta users
if (user.isBetaTester) {
config.set("features.betaAccess", true);
}
Use Case: NPM Package Configuration
import { createConfig } from "config-ship";
export function createClient(userOptions = {}) {
const config = createConfig({
defaults: {
timeout: 5000,
retries: 3,
baseURL: "https://api.example.com"
},
envPrefix: "MY_PKG_"
});
// User options override everything
Object.keys(userOptions).forEach(key => {
config.set(key, userOptions[key]);
});
return {
config,
// your API
};
}
Configuration sources
- Your defaults
- Env vars:
MY_PKG_TIMEOUT=10000 - Runtime:
createClient({ timeout: 3000 })
Security: Prototype Pollution Protection
Critical fix in v0.1.2:
// Malicious attempts are blocked ✅
config.set("__proto__.polluted", true);
config.set("constructor.prototype.polluted", true);
console.log({}.polluted); // undefined (safe!)
Tested with comprehensive security tests.
What’s New in v0.1.2?
- ✨ Raw env names –
config.get("APP_NAME")now works - 🔒 Security – Fixed prototype‑pollution vulnerability
- 💪 TypeScript – Strict mode enabled
- 📚 Docs – Better examples and use cases
- ✅ Tests – 37 tests, all passing
Why Not Just Use…?
| Library | Drawbacks |
|---|---|
| dotenv | Only loads env vars; no layering, no runtime overrides |
| config | 5+ dependencies, complex setup, no raw env names |
| convict | Great but heavy; validation overhead |
| ConfigShip | Zero deps, simple, secure, batteries‑included |
Installation
npm install config-ship
Links
- 📦 NPM:
- 🐙 GitHub:
- 📝 Changelog:
Try It
npm install config-ship
Would love your feedback! What config problems are you facing?
Edit: Thanks for all the feedback! Added clarification about env‑var naming and raw‑name support.
Subreddits to post to
- r/node
- r/javascript
- r/typescript
- r/webdev
- r/programming (if it gains traction)