DEV Community

kevin patil
kevin patil

Posted on

I built a free CLI that audits your Node.js + React project before you ship

Before shipping anything I'd run through the same mental checklist every time.

Did I forget any .env keys? Are there packages I added and never used? Did I leave that useState inside an if block?

Each check was a different tool. npm audit for vulns. depcheck for unused packages (unmaintained, misses a lot). React DevTools for re-renders (browser only, no CI). ESLint for hook violations (needs a whole config setup). Nothing for
.env files at all.

So I built devguard. One command.

npx @kevinpatil/devguard
** Env validation
**
This one I needed personally. I've shipped with JWT_SECRET=secret in production before. Not something I want to repeat.

devguard reads your .env against .env.example and flags:

  • Missing required keys
  • Empty values you forgot to fill in
  • Weak secrets (secret and changeme both count)
  • Type mismatches like PORT=abc
  • Malformed URLs

Output looks like this:

ERRORS (2)
✗ DATABASE_URL missing — required in .env.example
✗ JWT_SECRET insecure value: 'secret'

WARNINGS (1)
⚠ PORT value 'abc' is not a valid number
** Dependency audit
**
Three things: unused packages, outdated versions, vulnerabilities.

Unused detection is pure static analysis. It walks your source files, extracts every import, compares against package.json. No node_modules needed.

For vulnerabilities it hits OSV.dev (Google's free vuln database) with a single batch POST — all packages at once, not one request per package. No API key required.

UNUSED (3)
lodash, uuid, moment

VULNERABILITIES (1)
express@4.17.1 CVE-2024-29041 High

ALTERNATIVES
moment → dayjs saves 65KB, same API
lodash → native ES6 saves 71KB

React audit
**
Six checks, all static analysis, no browser needed.
**Dead imports
— walks your codebase, builds an import graph, finds components that are defined but used nowhere. Handles circular imports without hanging by tracking visited file paths.

Re-render risks — finds inline objects and functions passed as props:

// flagged — new object reference on every render
remove(id)} />

Use useMemo for objects, useCallback for functions passed as props.

Hook violations — catches hooks inside if blocks, loops, and nested functions. The one that burns people most often:

if (isLoggedIn) {
const [data, setData] = useState(null) // violation
}

Bundle size **— flags heavy packages with alternatives. moment at 67KB, lodash at 71KB, jquery at 87KB.
**Accessibility
— static JSX scan. img without alt, div with onClick, anchor without href. Reports file path and line number for each.
RSC boundaries — for Next.js App Router. Catches useState in server components, browser APIs like window in server components, and server-only imports inside client components.
*A few things I decided early on
*

No API keys for the core features. Everything that can be done statically, is. The alternatives list is embedded in the source — no external lookup at runtime. Only two outbound APIs: npm registry and OSV.dev, both free with no key
required.
All API results are cached at ~/.devguard/cache.json with a 24hr TTL keyed by name@version. Repeated runs are nearly instant and work offline.
No ESLint dependency. I wanted this to work on any project, not just ones with an existing lint setup. The hook violation checker is pure AST parsing via @babel/parser, which handles JSX and TSX with zero config.
** CI integration
**
# Fail the build if any errors are found
npx @kevinpatil/devguard --strict

# JSON output for custom pipelines
npx @kevinpatil/devguard --json

# SARIF report for GitHub Code Scanning
npx @kevinpatil/devguard --sarif

** Try it
**
npx @kevinpatil/devguard

MIT licensed, free, actively maintained. If it catches something useful or misses something it should catch, open an issue — I read them all.

Top comments (0)