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

@didrod2539/envlint

v0.1.0

Published

Lint .env files locally: sync against .env.example, validate syntax, detect hardcoded secrets (AWS, Stripe, GitHub, OpenAI, private keys…), and enforce an optional schema. Deterministic CLI, JSON/Markdown reports, no network — your secrets never leave the

Readme

🔐 envlint

Lint your .env files and catch leaked secrets — locally, before you commit.

npm version CI node license

A deterministic CLI that lints your .env files: syncs them against .env.example, validates syntax & hygiene, enforces an optional schema, and detects hardcoded secrets (AWS, Stripe, GitHub, OpenAI, private keys and more) — with a score, A–F grade and JSON/Markdown reports. Runs 100% locally; your secrets never leave your machine.


One-line summary

envlint compares your .env to its example, flags missing/extra/duplicate keys and value problems, and scans for real secrets accidentally committed — all offline, no API key, no server.

Why this project exists

.env files are where teams quietly hurt themselves:

  • A teammate adds STRIPE_SECRET_KEY but forgets .env.example, so everyone else's local build breaks and prod is missing a variable at runtime.
  • Someone pastes a real AWS or Stripe key into .env and it gets committed — now it's in git history, and rotating it is a fire drill.
  • Values drift: a PORT that isn't a number, a URL with an unquoted space that silently truncates, a placeholder changeme shipped to staging.

These are mechanical, high-stakes problems that belong in a pre-commit hook or CI gate, not in a code review someone skims. And because .env is sensitive, you can't just paste it into an LLM. envlint is the deterministic, local check.

Key features

  • 🔄 Sync against .env.example — missing keys, extra/undocumented keys.
  • 🔐 Secret detection — provider patterns (AWS, Stripe, GitHub, Google, OpenAI, Anthropic, Slack, Twilio, SendGrid, npm, JWTs, private keys) plus a Shannon-entropy fallback for opaque tokens. Placeholders are ignored.
  • 🧹 Syntax & hygiene — duplicate keys, invalid names, empty values, unquoted values with spaces, trailing whitespace, lowercase keys, placeholders.
  • 📐 Optional schematype (string/number/boolean/url/email/port), enum, pattern per key.
  • 📊 Score + A–F grade, per file and overall; secrets weigh heaviest.
  • 📄 JSON & Markdown export, colored console output, CI gate exit codes.
  • ⚙️ Config file, per-rule severities, ignore lists.
  • 🔒 Zero network. Secrets are masked in output and never transmitted.

Install

# run without installing
npx @didrod2539/envlint scan .env

# or install
npm install -g @didrod2539/envlint    # global CLI (provides `envlint`)
npm install -D @didrod2539/envlint    # project dev-dependency (for CI / hooks)

Node ≥ 18. ESM + CJS + TypeScript types.

Quick start

envlint scan .env
.env  0/100 (F)  10 keys vs .env.example
  ✗ Missing key "SESSION_TIMEOUT" (present in .env.example)
  ⚠ Key "EXTRA_DEBUG" is not in .env.example:21
  ✗ Duplicate key "ENABLE_SIGNUP" (lines 19, 20):20
  ⚠ Unquoted value with spaces for "DATABASE_URL" (line 8):8
  ✗ Possible JSON Web Token in "JWT_SECRET" (line 11):11
  ✗ Possible Stripe Secret Key in "STRIPE_SECRET_KEY" (line 14):14
  ✗ Possible AWS Access Key ID in "AWS_ACCESS_KEY_ID" (line 15):15

Overall  0/100 (F)  1 file(s), 10 key(s),  3 secret(s) , 8 error(s), 3 warning(s), 2 info

(envlint auto-finds .env.example / .env.sample / .env.template next to your file.)

CLI usage

envlint scan [...targets]     # lint .env files or directories
envlint report <input.json>   # re-render a saved JSON report as Markdown
envlint init                  # scaffold envlint.config.json (with a schema)
envlint --help
envlint --version

scan options:

| Option | Description | | --- | --- | | --config <file> | Path to a config file (otherwise auto-detected) | | --example <file> | Example/schema file to compare against | | --no-secrets | Disable secret scanning | | --json <file> | Write a JSON report | | --md <file> | Write a Markdown report | | --min-score <n> | Exit non-zero if the overall score < n (CI gate) | | --quiet | Hide info-level issues in the console |

Pointed at a directory, scan finds .env, .env.local, .env.production, etc. (skipping *.example/*.sample/*.template).

Example result

Full reports for the bundled sample files are in examples/sample-report.md and examples/sample-report.json.

📸 Screenshot / demo GIF placeholder: ./docs/screenshot.png — record the terminal running npx @didrod2539/envlint scan examples/.env.local.

Configuration

Create envlint.config.json (or run envlint init):

{
  "example": ".env.example",
  "scanSecrets": true,
  "entropyThreshold": 4.0,
  "entropyMinLength": 20,
  "minScore": 90,
  "allowEmpty": ["OPTIONAL_FLAG"],
  "ignoreKeys": ["LEGACY_*"],
  "disableRules": [],
  "ruleSeverity": { "lowercase-key": "warning" },
  "schema": {
    "PORT": { "type": "port" },
    "NODE_ENV": { "enum": ["development", "production", "test"] },
    "DATABASE_URL": { "type": "url" }
  }
}

| Field | Meaning | | --- | --- | | example | Example/schema file (auto-detected if null) | | scanSecrets | Enable provider/entropy secret scanning | | entropyThreshold / entropyMinLength | Tune the generic high-entropy check | | minScore | CI gate threshold (overridable with --min-score) | | allowEmpty | Keys allowed to have empty values | | ignoreKeys | Keys to skip — exact, or trailing-* prefix wildcard | | disableRules | Rule ids to turn off | | ruleSeverity | Override severity per rule id | | schema | Optional per-key type / enum / pattern constraints |

Rule ids: missing-keys, extra-keys, duplicate-key, invalid-key, empty-value, placeholder-value, unquoted-spaces, trailing-whitespace, lowercase-key, secret-detected, schema-*.

Real-world use cases

  1. Block secret leaks in a pre-commit hook. Add envlint scan .env --min-score 100 (or wire it into [husky]/lint-staged). A real AWS/Stripe key in .env fails the commit before it ever reaches git history.
  2. Keep .env.example honest in CI. Run envlint scan .env.ci --example .env.example. A PR that adds an env var without documenting it in the example fails the build, so onboarding never breaks.
  3. Audit a config you inherited. envlint scan . --md audit.md profiles every .env* file in a repo and produces a shareable report of what's missing, malformed, or dangerously hardcoded.

Programmatic API

import { analyze, buildReport, toMarkdown } from "@didrod2539/envlint";

const file = analyze({ source: ".env", content, reference: { source: ".env.example", content: ex } });
console.log(file.score, file.secrets, file.issues);

const report = buildReport([file], { version: "0.1.0" });
await fs.writeFile("report.md", toMarkdown(report));

Roadmap

  • A bundled pre-commit hook / husky recipe and a GitHub Action.
  • --fix to sync missing keys into .env and quote unquoted values.
  • More provider secret patterns (Azure, GCP service accounts, DigitalOcean…).
  • .env.vault / multi-environment diffing (.env vs .env.production).
  • Allowlist file for known-safe values (e.g. test fixtures).
  • Baseline mode to ignore pre-existing findings and only fail on new ones.

FAQ

Does envlint send my .env anywhere? No. It runs entirely on your machine — no API key, no telemetry, no uploads, no network calls. Detected secrets are masked in all output.

How does secret detection work? A curated set of provider regexes (AWS, Stripe, GitHub, OpenAI, etc.) plus a Shannon-entropy fallback for long, random, opaque tokens. Obvious placeholders (your-key-here, changeme, <token>) are deliberately ignored. See src/secrets.ts.

Won't the entropy check have false positives? It's conservative (length + character-class + entropy threshold, all tunable via config), and you can --no-secrets or ignoreKeys anything. Prefer a missed edge case over noise.

Is it safe to keep example secrets in the repo? Yes — that's the point of .env.example: it should contain only placeholders. envlint flags when a real-looking secret appears so the example stays clean.

Does it work with my framework? Any project using dotenv-style files: Node, Next.js, Vite, Rails, Django, Docker --env-file, etc. It parses the common .env grammar (quotes, export, comments).

Is the score official? No — it's a transparent metric (severity-weighted penalties, with a heavy extra penalty per detected secret). Use it to track and gate. See src/score.ts.

Contributing

Contributions welcome! Each check is a small, self-contained rule in src/rules/, and secret patterns are a declarative table in src/secrets.ts. See CONTRIBUTING.md and the Code of Conduct.

git clone https://github.com/didrod205/envlint.git
cd envlint
npm install
npm test
npm run build
node dist/cli.js scan examples/.env.local --example examples/.env.example

License

MIT © envlint contributors

💖 Sponsor

envlint is free, MIT-licensed, and built in spare time. If it stopped a secret from hitting your git history, please consider supporting it:

Where your support goes: more secret patterns, a pre-commit hook + GitHub Action, a --fix mode, multi-environment diffing, and fast issue responses.