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)