Node Adapter
The @ctroenv/node package provides .env file loading and process.env access for
Node.js applications.
Installation
npm install @ctroenv/nodeloadEnv()
Loads environment variables from .env files in a priority chain.
function loadEnv(opts?: LoadEnvOptions): EnvSourceOptions
interface LoadEnvOptions {
path?: string
encoding?: BufferEncoding
override?: boolean
system?: boolean
}| Option | Type | Default | Description |
|---|---|---|---|
path | string | process.cwd() | Root directory to search for .env files |
encoding | BufferEncoding | "utf-8" | File encoding |
override | boolean | false | If false, process.env takes priority |
system | boolean | false | Fall back to process.env when key not in files |
File Priority Chain
Files are loaded in order, with later files overriding earlier ones:
.env.env.{NODE_ENV}(e.g.,.env.development).env.local
Usage
import { defineEnv } from "@ctroenv/core"
import { loadEnv } from "@ctroenv/node"
const env = defineEnv(schema, {
source: loadEnv(),
})Override Behavior
By default, process.env takes priority over file values:
// process.env.DATABASE_URL always wins
const source = loadEnv()
// .env files override process.env
const source = loadEnv({ override: true })nodeSource()
A simpler alternative that only wraps process.env:
function nodeSource(): EnvSourceimport { defineEnv } from "@ctroenv/core"
import { nodeSource } from "@ctroenv/node"
const env = defineEnv(schema, {
source: nodeSource(),
})This is equivalent to not passing a source at all (the default auto-detection uses
process.env in Node.js), but is useful for explicit readability.
parseEnvFile()
Parses a .env file string into key-value pairs. Supports the full .env file syntax.
function parseEnvFile(content: string): Record<string, string>Features
| Feature | Example | Result |
|---|---|---|---|
| Comments | KEY=val # comment | { KEY: "val" } |
| export prefix | export KEY=val | { KEY: "val" } |
| Quoted values | KEY="hello world" | { KEY: "hello world" } |
| Multiline (trailing \) | KEY=line one\line two | { KEY: "line one\nline two" } |
| Variable interpolation | URL=$BASE/api or URL=\${BASE}/api | Resolved from earlier keys, then process.env |
| Escaped $ with $$ | KEY=price$$10 | { KEY: "price$10" } |
| Escaped quotes | KEY=it's fine or KEY="say \"hi\"" | Preserves literal quotes |
Usage
import { parseEnvFile } from "@ctroenv/node"
import { readFileSync } from "node:fs"
const content = readFileSync(".env", "utf-8")
const env = parseEnvFile(content)
// env.DATABASE_URL => "postgres://localhost/db"Interpolation Behavior
Variables are resolved from previously parsed keys in the same file, then
falls back to process.env. Forward references are not supported —
variables must be defined before they are used.
BASE_URL=http://localhost:3000
API_URL=${BASE_URL}/api/v1
# API_URL => "http://localhost:3000/api/v1"EnvSource Type
The EnvSource type is re-exported for convenience:
import type { EnvSource } from "@ctroenv/node"
function customSource(): EnvSource {
return {
get(key: string): string | undefined {
return process.env[key] ?? myCustomStore[key]
},
}
}