npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

genenv-cli

v2.0.2

Published

Generate typed environment configs from your .env file

Readme

genenv

Generate typed, framework-aware environment configs from a .env file — straight from the command line.

[!IMPORTANT] Package renamed: genenv-config is now genenv-cli. If you previously installed genenv-config, uninstall and reinstall:

npm uninstall -g genenv-config
npm install -g genenv-cli

Since v2.0.2: this rename notice still applies — the package name and genenv command introduced with the rename are unchanged in 2.0.2. Replace this line with your actual 2.0.1 → 2.0.2 changelog notes if there are behavior changes to call out.


Table of Contents

  1. Project Overview
  2. Why Use This CLI?
  3. Pros and Cons
  4. Installation
  5. Quick Start
  6. CLI Commands
  7. CLI Flags and Options
  8. Command Examples
  9. Sample Generated Output
  10. Input Parsing Rules
  11. Common Use Cases
  12. Automation and Scripting
  13. Error Handling
  14. Troubleshooting
  15. Best Practices
  16. Building From Source
  17. FAQ
  18. License

1. Project Overview

genenv is a CLI tool that reads a .env file and generates a ready-to-import environment module (env.ts, optionally env.js, and optionally .env.example) shaped for a specific JavaScript runtime or framework — Node, Express, Next.js, Remix, Vite, Astro, Bun, or Deno.

It parses your .env file into typed key/value entries, inferring string, number, or boolean for each value, then writes a generated file that reads those keys from the correct runtime API (process.env, import.meta.env, or Deno.env) with appropriate type casting. Optionally, it generates a Zod-validated schema instead of a plain cast, so invalid or missing variables fail fast at startup.

Who it's for: developers who want type-safe, IDE-friendly access to environment variables without hand-writing and maintaining that boilerplate every time .env changes.

Main workflow:

  1. Keep .env as the source of truth for your environment variables.
  2. Run genenv init (first time) or genenv generate (subsequent runs) to regenerate the env module.
  3. Import the generated file from your application code.

CLI-only tool. genenv is not designed to be imported as a JavaScript/TypeScript library — attempting to require/import it programmatically causes it to print an error and exit.

Don't want to install anything? You can run every command in this README through npx instead of a global install — see Run without installing (npx).


2. Why Use This CLI?

  • Removes hand-written boilerplate — no more manually writing Number(process.env.PORT) casts and null checks for every variable.
  • Framework-aware output — generates the correct access pattern (process.env, import.meta.env, or Deno.env.get()) for 8 different targets.
  • Type inference — automatically infers string, number, or boolean per variable from the .env file, no manual annotation needed.
  • Optional runtime validation — the --zod flag generates a schema that throws a clear error if a required variable is missing or malformed.
  • Optional .env.example — pass --example to generate a safe-to-commit template alongside your typed module.
  • Scriptable — both commands are non-interactive and exit with a non-zero code on failure, making them usable in npm scripts, pre-build steps, or CI.
  • Zero-config onboardinggenenv init detects your framework from package.json and installs dotenv automatically when needed.
  • No global install required — run it on demand with npx if you'd rather not add a global binary.

When it may not be the right choice: if you don't want a generated source file checked into your project, need to merge multiple .env files in one run, need config formats beyond simple KEY=value pairs, or need scientific-notation numeric parsing.


3. Pros and Cons

Pros

  • Zero-config init mode with automatic framework detection and dotenv installation.
  • Framework-specific env access code for 8 targets (Node, Express, Next.js, Remix, Vite, Astro, Bun, Deno).
  • Automatic type inference (string / number / boolean) from .env values.
  • Optional Zod-based runtime validation with clear failure messages.
  • Output directory is created automatically if it doesn't exist.
  • Colorized, readable console output summarizing what was parsed and generated.
  • No required runtime dependency for the default (non-Zod) output.
  • Works via npx with no global install.

Cons

  • No persistent configuration file — every run relies entirely on CLI flags.
  • Only a single .env file can be parsed per run (no multi-file merging).
  • Number inference does not support scientific notation (1e3 is treated as a string).
  • The generated env.js mixes a "use strict" header with an ES module export default statement — confirm it matches your project's module system before using it.
  • No --version flag; the version string is only visible inside --help output.
  • Running genenv with no arguments (or a bare word like genenv next) only prints help — it does not run init. You must run genenv init or genenv generate explicitly.
  • All output, including errors, is written to stdout rather than stderr.
  • Minimum Node.js version and supported operating systems are not confirmed — Needs verification.

4. Installation

Prerequisites

  • Node.js (minimum version — Needs verification).
  • A package manager: npm, yarn, pnpm, or bun.

Package name vs. command name: the npm package is published as genenv-cli, but installing it puts a genenv command on your PATH. Install using the package name; run using the command name.

Global install

# npm
npm install -g genenv-cli

# yarn (needs verification)
yarn global add genenv-cli

# pnpm (needs verification)
pnpm add -g genenv-cli

Run without installing (npx)

If you don't want a global install — for example, in a one-off script or a CI job you don't want to maintain — run it directly with npx.

The npm package is named genenv-cli, but its package.json only declares one entry in bin:

"bin": {
  "genenv": "dist/cli.js"
}

Because there's exactly one bin script, npx resolves it automatically — you don't need to spell out genenv a second time or pass -p/--package:

npx genenv-cli init
npx genenv-cli generate --next --zod
npx genenv-cli --help

This works even if genenv has never been installed globally or locally — npx fetches genenv-cli on demand for that single run, sees it has one bin, and runs genenv from it.

Already have it installed? Once genenv-cli is a local dependency (after npm install), installed globally, or linked with npm link, the genenv binary already exists on your machine — so you can drop -cli entirely and just run:

genenv init
genenv generate --next --zod

-cli only needs to appear the one time you tell npx which package to fetch. After that, every command you actually type is just genenv.

Verifying the installation

There is no --version flag. Verify by running:

genenv --help
# or, without a global install:
npx genenv-cli --help

This prints the version string as part of the help output.


5. Quick Start

With a global install:

npm install -g genenv-cli
genenv init

With npx (no install):

npx genenv-cli init

Either way, init reads .env from the current directory, detects your framework from package.json (falling back to Node.js), installs dotenv automatically if needed, and writes env.ts to src/lib/. Pass --example to also generate .env.example in the same output directory.


6. CLI Commands

init

Zero-config, opinionated setup — the recommended starting point for a new project.

  • Default output directory: src/lib/
  • Framework auto-detection: checks package.json dependencies in order — nextremix/@remix-run/nodeastroviteexpress — falling back to node.
  • dotenv auto-install: runs automatically for Node, Express, and Remix targets (not needed for Next, Vite, Astro, Bun, or Deno).
genenv init
genenv init --next --zod
genenv init --express --zod --example

generate

Explicit, non-opinionated generation with full flag control. Does not auto-detect the framework and does not auto-install dotenv. Best for CI and automation.

  • Default output directory: . (current directory)
genenv generate
genenv generate --remix --zod
genenv generate --vite -i apps/web/.env -o apps/web/src/lib

Note: running genenv with no command, or with an unrecognized bare word like genenv next, only prints help. See Troubleshooting.


7. CLI Flags and Options

| Flag | Short | Default | Description | | ------------- | ------ | --------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | --input | -i | .env | Path to the source.env file to parse. | | --output | -o | . (generate) / src/lib (init) | Directory the generated files are written into. Created automatically if missing. When omitted, files are written to the project root (forgenerate) or src/lib/ (for init). | | --name | -n | env | Base file name (without extension) for the generated env module.--name appEnvappEnv.ts / appEnv.js. | | --zod | — | false | Generates a Zod-validatedenv.ts instead of a plain typed one. Requires zod to be installed. | | --js | — | false | Also emitsenv.js alongside env.ts. | | --example | — | false | Generates.env.example in the same output directory as env.ts. Opt-in — off by default. | | --node | — | (auto) | Target Node.js (process.env). | | --express | — | — | Target Express (process.env). | | --vite | — | — | Target Vite (import.meta.env). | | --next | — | — | Target Next.js (process.env; Next loads .env natively). | | --remix | — | — | Target Remix (server-onlyprocess.env). | | --astro | — | — | Target Astro (import.meta.env). | | --bun | — | — | Target Bun (process.env; Bun auto-loads .env). | | --deno | — | — | Target Deno (Deno.env.get()). | | --help | -h | — | Prints usage and exits. |

Only one framework flag may be used per run — passing two throws: Multiple frameworks specified: ... Pick one.

Output file locations

| File | Default location | With-o src/lib | | ---------------- | ------------------------------------------------------ | ------------------------ | | env.ts | Project root (generate) or src/lib/ (init) | src/lib/env.ts | | env.js | Same asenv.ts | src/lib/env.js | | .env.example | Same directory asenv.ts | src/lib/.env.example |

.env.example always lands in the same directory as env.ts — wherever that is. It is not hardcoded to the project root.


8. Command Examples

# Zero-config setup (auto-detects framework)
genenv init

# Init for Next.js with Zod validation
genenv init --next --zod

# Generate for Node (default), output to current directory
genenv generate

# Generate for Remix with Zod validation
genenv generate --remix --zod

# Generate for Vite with custom input and output paths
genenv generate --vite -i apps/web/.env -o apps/web/src/lib

# Generate for Deno into a specific output directory
genenv generate --deno -o src/lib

# Also emit env.js alongside env.ts
genenv generate --bun --js

# Generate with .env.example in the same output directory
genenv generate --example

# Custom output file base name → appEnv.ts
genenv generate --name appEnv

# Show help and version string
genenv --help

Not installed? Swap genenv for npx genenv-cli in any of the above — see Run without installing (npx).


9. Sample Generated Output

Given this .env file:

PORT=3000
DATABASE_URL=postgres://localhost/myapp
DEBUG=true

Running genenv generate --node produces env.ts:

import "dotenv/config";

function requireString(key: string): string {
  const val = process.env[key];
  if (val === undefined || val === "") throw new Error(`Missing env var: ${key}`);
  return val;
}

function requireNumber(key: string): number {
  const val = process.env[key];
  if (val === undefined || val === "") throw new Error(`Missing env var: ${key}`);
  const n = Number(val);
  if (isNaN(n)) throw new Error(`Env var ${key} is not a valid number: "${val}"`);
  return n;
}

function requireBoolean(key: string): boolean {
  const val = (process.env[key] ?? "").toLowerCase();
  return val === "true";
}

const env = {
  PORT: requireNumber("PORT"),
  DATABASE_URL: requireString("DATABASE_URL"),
  DEBUG: requireBoolean("DEBUG"),
};

export default env;

Running genenv generate --node --zod instead produces a Zod-validated env.ts:

import "dotenv/config";
import { z } from "zod";

export const EnvSchema = z.object({
  PORT: z.coerce.number(),
  DATABASE_URL: z.string().min(1),
  DEBUG: z.enum(["true", "false"]).transform((v) => v === "true"),
});

const env = EnvSchema.parse(process.env);

export default env;

Running with --vite swaps process.env for import.meta.env throughout, and omits the dotenv import (Vite loads .env natively). Running with --deno uses Deno.env.get(key) instead.


10. Input Parsing Rules

Source file: .env by default; override with -i/--input.

Line parsing:

  • Blank lines and lines starting with # are skipped.
  • Lines without = are skipped.
  • Inline comments are stripped only when preceded by a space — VALUE # comment strips the comment, but VALUE#comment keeps the # as part of the value.
  • A single matching pair of surrounding " or ' quotes is stripped from the value.
  • Duplicate keys: the last value wins, but the key keeps the position where it was first seen.

Type inference:

| Type | Detected when | | ----------- | ------------------------------------------------------------------------------------ | | boolean | Value istrue or false (case-insensitive) | | number | Integer, negative, or decimal:42, -3.14, .5, Infinity, -Infinity | | string | Anything else, including empty values |

Scientific notation (1e3) and trailing-dot decimals (5.) are not recognized as numbers and are treated as strings.

Framework env access in generated code:

| Flag | Access pattern | dotenv auto-installed by init? | | -------------------- | ------------------- | -------------------------------------- | | --node (default) | process.env | Yes | | --express | process.env | Yes | | --remix | process.env | Yes | | --next | process.env | No — Next loads.env natively | | --vite | import.meta.env | No — Vite loads.env natively | | --astro | import.meta.env | No — Astro loads.env natively | | --bun | process.env | No — Bun auto-loads.env | | --deno | Deno.env.get() | No — built in |


11. Common Use Cases

Bootstrapping a new Next.js project

genenv init

Auto-detects Next.js from package.json, skips the dotenv install, and writes env.ts to src/lib/.

Adding fail-fast validation to an Express API

genenv generate --express --zod

Requires zod to be installed. Generates a schema that throws at startup if a required variable is missing or malformed.

Generating Vite-safe env types for a frontend app

genenv generate --vite -o src/lib

Uses import.meta.env instead of process.env, matching Vite's client-side env handling.

Keeping .env.example in sync as .env changes

genenv generate --example

Regenerates both env.ts and .env.example in the same directory. Pass --example each time — it's opt-in.

Multiple env modules in one project

genenv generate --name serverEnv -i .env.server
genenv generate --name clientEnv -i .env.client --vite

Using -n/--name prevents one run from overwriting the other's output.

One-off use without installing anything

npx genenv-cli generate --example

Handy for a quick check on a machine where you don't want to add a global binary.


12. Automation and Scripting

Both commands are non-interactive and exit with code 1 on failure, making them safe for npm scripts, pre-build hooks, and CI:

{
  "scripts": {
    "env:generate": "genenv generate --zod --example",
    "prebuild": "genenv generate"
  }
}

If you'd rather not add genenv-cli as a dependency at all, call it through npx instead:

{
  "scripts": {
    "env:generate": "npx genenv-cli generate --zod --example",
    "prebuild": "npx genenv-cli generate"
  }
}

In CI, prefer genenv generate over init — it skips auto-detection and auto-install, giving deterministic, dependency-safe behavior. Check the exit code to fail the build on a missing or invalid .env; do not parse stderr, since all output goes to stdout.


13. Error Handling

| Situation | Message | Exit code | | ------------------------------------------------------- | -------------------------------------------------------------------------------------------- | --------- | | Two framework flags passed | Multiple frameworks specified: <flagA> and <flagB>. Pick one. | 1 | | -i, -o, or -n given with no following value | Missing value for <flag> <path/name> | 1 | | Unrecognized flag (starts with-) | Unknown flag: <flag>. Run genenv --help to see available options. | 1 | | Input.env file not found | File not found: <path> | 1 | | --zod used without zod installed | Cannot generate a Zod schema: the "zod" package is not installed… + npm install zod | 1 | | Filesystem error (permissions, disk full, etc.) | Propagated from Node'sfs module | 1 |

A bare word that isn't init, generate, or a recognized --flag is silently ignored rather than producing an error.

Exit codes: 0 on success or when --help is shown; 1 on any error.


14. Troubleshooting

genenv with no arguments only prints help, even though the help text implies it runs init. The CLI requires an explicit command. Run genenv init explicitly.

genenv next does nothing and prints help. Framework names are only recognized as --flags. Use genenv init --next or genenv generate --next.

File not found: .env No .env file exists at the default path or the path given via -i. Create the file or pass the correct path: genenv generate -i path/to/.env.

Cannot generate a Zod schema: the "zod" package is not installed… Run npm install zod, then re-run your genenv command.

dotenv wasn't installed automatically. Automatic installation only happens with genenv init, not genenv generate, and only for Node, Express, and Remix targets. Run genenv init, or install dotenv manually.

The generated env.js fails to load in a CommonJS context. env.js is written with a "use strict" header but ends with export default (ES module syntax). Ensure your project uses ES modules, or adjust the export before importing.

.env.example didn't appear — or appeared in the wrong place. --example is opt-in and must be passed explicitly. When it is passed, .env.example is written to the same directory as env.ts (controlled by -o/--output). If you didn't pass -o, that's the project root for generate or src/lib/ for init.

npm install -g genenv fails or installs the wrong package. The npm package name is genenv-cli. Install with npm install -g genenv-cli; the genenv command becomes available afterward. If you don't want a global install at all, use npx genenv-cli <command> instead.


15. Best Practices

  • Commit .env.example, never .env.
  • Re-run genenv generate whenever .env changes — hook it to prebuild or a CI step.
  • Prefer --zod for services where a missing variable should fail fast at startup rather than surface later as a runtime bug.
  • Pass the framework flag that matches your actual runtime. Using --vite in a Node server generates import.meta.env access, which doesn't exist there.
  • Use genenv init only for first-time setup; use genenv generate for repeatable CI runs.
  • Use -n/--name when generating more than one env module in the same project.
  • In scripts, check the process exit code — don't parse stderr, because all output including errors goes to stdout.
  • When documenting installation for others, always pair the package name (genenv-cli) with the command name (genenv) to avoid confusion.
  • If contributors shouldn't need a global install, prefer npx genenv-cli ... in scripts and docs over assuming genenv is on everyone's PATH.

16. FAQ

What does this CLI do? It parses a .env file and generates a typed, framework-specific module (env.ts, optionally env.js) and an optional .env.example, eliminating hand-written environment variable access and casting.

How do I install it? npm install -g genenv-cli. The npm package is genenv-cli; the CLI command it installs is genenv. Prefer not to install anything? Use npx genenv-cli <command> instead.

How do I check which version I have? Run genenv --help — the version string appears in the help output. There is no standalone --version flag.

Does .env.example get generated automatically? No — pass --example to generate it. It is written to the same directory as env.ts.

Can I change the generated file's name? Yes — pass -n/--name <name>. Default is envenv.ts/env.js.

What Node.js versions are supported? Not specified in the project files — needs verification.

Does it work on Windows, macOS, and Linux? Not confirmed — needs verification.

Does it support JavaScript output? Yes — pass --js to also generate a CommonJS-style env.js alongside env.ts. Note the module system caveat in Troubleshooting.

How do I configure it? Entirely through CLI flags and your .env file. There is no config file.

How do I see available commands and flags? genenv --help (or -h), or npx genenv-cli --help if you haven't installed it.

How do I build the CLI itself from source? See Building From Source — clone the repo, npm install, then npm run build.

What are the main limitations? No config file, single-file .env input only, no scientific-notation number parsing, no --version flag, and bare-word commands are silently ignored rather than producing an error.


17. License

MIT License

Copyright (c) genenv contributors

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.