
Security News
Axios Maintainer Confirms Social Engineering Attack Behind npm Compromise
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.
Automatically map process.env to strongly-typed, nested config objects with camelCase fields
Automatically map process.env entries to strongly-typed config objects with camelCase fields and nested structures.
PORT_NUMBER → { portNumber } or { port: { number } } depending on your schemaPORT_NUMBER=1234 → { portNumber: 1234 } (single entry stays flat)LOG_LEVEL + LOG_PATH → { log: { level: ..., path: ... } } (multiple entries get nested)APP_)ToEnv<T>, FromEnv<T>, WithPrefix<T> for type-level transformationsnpm install configenvy
# or
pnpm add configenvy
# or
yarn add configenvy
import { configEnvy } from 'configenvy';
// Given these environment variables:
// PORT_NUMBER=3000 <- single PORT_* entry, stays flat
// LOG_LEVEL=debug <- multiple LOG_* entries, gets nested
// LOG_PATH=/var/log
// DATABASE_HOST=localhost <- multiple DATABASE_* entries, gets nested
// DATABASE_PORT=5432
const config = configEnvy();
// Result:
// {
// portNumber: 3000, // flat (only one PORT_* entry)
// log: { // nested (multiple LOG_* entries)
// level: 'debug',
// path: '/var/log'
// },
// database: { // nested (multiple DATABASE_* entries)
// host: 'localhost',
// port: 5432
// }
// }
import { configEnvy } from 'configenvy';
// Load all environment variables
const config = configEnvy();
// Given: APP_PORT=3000, APP_DEBUG=true, OTHER_VAR=ignored
const config = configEnvy({ prefix: 'APP' });
// Result: { port: 3000, debug: true }
When you provide a schema, configenvy uses the schema structure to determine nesting. This gives you full control over the output shape:
import { configEnvy } from 'configenvy';
import { z } from 'zod';
// The schema defines exactly how env vars map to your config
const schema = z.object({
portNumber: z.number(), // PORT_NUMBER -> portNumber (flat)
log: z.object({ // LOG_LEVEL -> log.level (nested)
level: z.enum(['debug', 'info', 'warn', 'error']),
path: z.string() // LOG_PATH -> log.path
}),
database: z.object({
host: z.string(), // DATABASE_HOST -> database.host
port: z.number(), // DATABASE_PORT -> database.port
ssl: z.boolean().default(false)
})
});
// Given: PORT_NUMBER=3000, LOG_LEVEL=debug, LOG_PATH=/var/log, DATABASE_HOST=localhost, DATABASE_PORT=5432
const config = configEnvy({ schema, prefix: 'APP' });
// Result matches schema structure exactly:
// {
// portNumber: 3000,
// log: { level: 'debug', path: '/var/log' },
// database: { host: 'localhost', port: 5432, ssl: false }
// }
// TypeScript knows: config.portNumber is number, config.log.level is 'debug' | 'info' | 'warn' | 'error'
import { createConfigEnvy } from 'configenvy';
import { z } from 'zod';
const schema = z.object({
port: z.number(),
debug: z.boolean()
});
// Create a reusable loader with preset options
const loadConfig = createConfigEnvy({
prefix: 'APP',
schema
});
// Use in your app
const config = loadConfig();
// Override for testing
const testConfig = loadConfig({
env: { APP_PORT: '3000', APP_DEBUG: 'true' }
});
By default, each underscore creates a new nesting level. Use delimiter: '__' for double-underscore nesting:
// Given: LOG__LEVEL=debug, LOG__FILE_PATH=/var/log
const config = configEnvy({ delimiter: '__' });
// Result: { log: { level: 'debug', filePath: '/var/log' } }
// Note: Single underscores become camelCase within the segment
const config = configEnvy({ coerce: false });
// All values remain strings
configEnvy(options?)Parse environment variables into a nested config object.
| Option | Type | Default | Description |
|---|---|---|---|
env | NodeJS.ProcessEnv | process.env | Custom environment object |
prefix | string | - | Only include vars starting with this prefix |
schema | z.ZodType | - | Zod schema for validation, type inference, and structure guidance |
coerce | boolean | true | Auto-convert strings to numbers/booleans |
delimiter | string | '_' | Delimiter for nesting (e.g., '__' for double underscore) |
createConfigEnvy(defaultOptions)Create a reusable config loader with preset options.
const loadConfig = createConfigEnvy({ prefix: 'APP', schema: mySchema });
const config = loadConfig(); // Uses defaults
const testConfig = loadConfig({ env: testEnv }); // Override env
configenvy exports type utilities to help with type-safe environment variable handling:
ToEnv<T>Convert a nested config type to a flat SCREAMING_SNAKE_CASE env record:
import type { ToEnv } from 'configenvy';
type Config = {
portNumber: number;
log: {
level: string;
path: string;
};
};
type Env = ToEnv<Config>;
// {
// PORT_NUMBER: string;
// LOG_LEVEL: string;
// LOG_PATH: string;
// }
FromEnv<T>Convert flat env keys to camelCase (uses type-fest's CamelCasedPropertiesDeep):
import type { FromEnv } from 'configenvy';
type Env = { PORT_NUMBER: string; LOG_LEVEL: string };
type Config = FromEnv<Env>;
// { portNumber: string; logLevel: string }
WithPrefix<T, P> / WithoutPrefix<T, P>Add or remove prefixes from env keys:
import type { WithPrefix, WithoutPrefix } from 'configenvy';
type Env = { PORT: string; DEBUG: string };
type PrefixedEnv = WithPrefix<Env, 'APP'>;
// { APP_PORT: string; APP_DEBUG: string }
type Unprefixed = WithoutPrefix<PrefixedEnv, 'APP'>;
// { PORT: string; DEBUG: string }
SchemaToEnv<T>Extract env type from a Zod schema's inferred type:
import type { SchemaToEnv } from 'configenvy';
import { z } from 'zod';
const schema = z.object({
port: z.number(),
log: z.object({ level: z.string() })
});
type Env = SchemaToEnv<z.infer<typeof schema>>;
// { PORT: string; LOG_LEVEL: string }
| Input | Output |
|---|---|
'true', 'TRUE', 'True' | true |
'false', 'FALSE', 'False' | false |
'123', '-42' | 123, -42 (integers) |
'3.14', '-2.5' | 3.14, -2.5 (floats) |
| Other strings | Unchanged |
MIT
FAQs
Automatically map process.env to strongly-typed, nested config objects with camelCase fields
The npm package envyconfig receives a total of 24 weekly downloads. As such, envyconfig popularity was classified as not popular.
We found that envyconfig demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.

Security News
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.