███████╗███╗ ██╗██╗ ██╗ ██╗ ██████╗ ██╗ ██╗
██╔════╝████╗ ██║██║ ██║ ██║██╔═══██╗╚██╗ ██╔╝
█████╗ ██╔██╗ ██║██║ ██║ ██║██║ ██║ ╚████╔╝
██╔══╝ ██║╚██╗██║╚██╗ ██╔╝██ ██║██║ ██║ ╚██╔╝
███████╗██║ ╚████║ ╚████╔╝ ╚█████╔╝╚██████╔╝ ██║
╚══════╝╚═╝ ╚═══╝ ╚═══╝ ╚════╝ ╚═════╝ ╚═╝
Keep your .env in sync with .env.example.
Add a key to .env, forget to update .env.example, and your teammate's app
breaks on boot. envjoy compares the two files you already keep and tells you
exactly what drifted — missing, empty, or extra keys. No schema, no config, no
accounts.
$ npx @vtx-labs/envjoy
✗ Missing 2 (in example, not in env)
- STRIPE_SECRET_KEY
- REDIS_URL
● Empty 1 (present but no value)
○ DATABASE_URL
+ Extra 1 (in env, not in example)
+ DEBUG_FLAG
4 ok · run `envjoy --fix` to add missing keys · `--check` for CInpx @vtx-labs/envjoy # report drift (no install)
envjoy --fix # scaffold missing keys into .env
envjoy --check # exit non-zero on drift (CI / pre-commit)
envjoy --generate # create .env.example from .env, values strippedOr add it to a project: pnpm add -D @vtx-labs/envjoy
Those load variables or validate against a schema you hand-write. envjoy
validates against the .env.example your team already maintains — nothing
extra to keep in sync, and zero runtime dependencies.
envjoy [options]
-e, --env <file> Env file to check (default: .env)
-x, --example <file> Source of truth (default: .env.example)
--fix Append missing keys to the env file (placeholders)
--check, --ci Exit non-zero on drift; makes no changes
--generate Write <example> from <env>, with values stripped
-f, --force Allow --generate to overwrite an existing example
--no-extra Ignore keys in env but not in example
--no-empty Ignore empty values in env
--ignore <keys> Comma-separated keys to skip (e.g. NODE_ENV,PORT)
-h, --help Show help
-v, --version Show version
| Exit code | Meaning |
|---|---|
0 |
In sync, or a non---check command succeeded |
1 |
Drift (or duplicate keys) detected in --check mode |
2 |
Usage error or a required file was not found |
# .github/workflows/ci.yml — fail the build if .env drifts
- run: npx @vtx-labs/envjoy --check --no-emptyThe library half is pure and dependency-free.
import { diffEnv } from "@vtx-labs/envjoy";
import { readFileSync } from "node:fs";
const diff = diffEnv(
readFileSync(".env.example", "utf8"),
readFileSync(".env", "utf8"),
{ ignore: ["NODE_ENV"] },
);
if (!diff.inSync) console.error("Drift:", { ...diff });| Export | Description |
|---|---|
diffEnv(example, actual, options?) |
Compare two env strings → EnvDiff |
applyMissing(example, actual) |
Env content with missing keys appended |
generateExample(actual) |
Build an example (values stripped) from an env |
parseEnv(content) |
dotenv-compatible parser → entries, map, duplicates |
envjoy parses both files with a dotenv-compatible parser — export
prefixes, single/double/back-quoted and multiline values, \n/\t escapes,
inline and full-line # comments, CRLF, and a UTF-8 BOM — then does a set
comparison. Malformed lines are skipped, never fatal. --fix only ever adds
missing keys using the example's placeholders; it never copies real values.