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

envpin

v0.1.0

Published

env config with a schema, a boot time report and a lockfile so drift is a diff

Readme

envpin

env config with a schema, a boot time report and a lockfile so drift is a diff.

zero deps. node 18+.

npm i envpin

why

most env handling fails one key at a time. you fix DATABASE_URL, restart, and now STRIPE_KEY is missing. five restarts later you are up. envpin reports every problem in one go, then hands you typed values.

it also writes a lock of the schema shape — never the values — so a teammate adding a required key shows up as a diff in code review instead of a page at 3am.

use

import { loadOrThrow } from 'envpin'

const env = loadOrThrow({
  PORT: { kind: 'port', default: 3000 },
  DATABASE_URL: { kind: 'url', describe: 'primary postgres' },
  LOG_LEVEL: { kind: 'enum', values: ['debug', 'info', 'warn'], default: 'info' },
  STRIPE_KEY: { secret: true },
  WORKERS: { kind: 'number', min: 1, max: 64, default: 4 }
})

env.PORT      // 3000, a number
env.DEBUG     // false, a boolean

a bad boot prints everything at once and exits:

env config failed: 2 errors
  ✗ DATABASE_URL  is required (url) - primary postgres
  ✗ STRIPE_KEY    is required
  ! APP_TYOP      set but not in the schema

kinds

| kind | accepts | gives back | |---|---|---| | string | anything | string | | number | numeric, honours min / max | number | | port | integer 1..65535 | number | | boolean | 1 true yes on / 0 false no off | boolean | | url | anything new URL() takes | string | | enum | one of values | string | | json | valid json | parsed |

default also covers the empty string, because PORT= in a .env is unset in every way that matters.

anything with no default is required unless you say required: false.

secrets

secret: true does two things.

it keeps the value out of summarize():

import { load, summarize } from 'envpin'
const { values } = load(schema)
console.log(summarize(schema, values))
//   PORT                     3000
//   STRIPE_KEY               [redacted]

and it warns when a live-looking key turns up outside production:

! STRIPE_KEY  looks like a production credential but NODE_ENV is development

that one is a warning, not an error. it does not block boot — it is there for the moment someone copies prod .env to their laptop. matches sk_live_, rk_live_, AKIA, ghp_, npm_.

the lock

import { lockOf, diff } from 'envpin'
import previous from './env.lock.json' with { type: 'json' }

const d = diff(previous, lockOf(schema))
if (!d.ok) {
  console.log('added', d.added)      // ['NEW_KEY']
  console.log('removed', d.removed)
  console.log('changed', d.changed)  // [{ key: 'PORT', from: 'port', to: 'number' }]
  process.exit(1)
}

the lock is a sha256 over key name, kind, required, secret, has-default — sorted, so key order in your file never moves the hash. no value ever goes in. commit env.lock.json.

cli

npx envpin check ./env.schema.js     # diff schema against env.lock.json
npx envpin write ./env.schema.js     # write the lock

the schema module default-exports the schema object. check exits 1 on drift, so it drops into ci as one line.

api

  • load(schema, env?, opts?){ values, problems, lock }, never throws
  • loadOrThrow(schema, env?, opts?)values, throws EnvError with the whole report
  • lockOf(schema)Lock
  • diff(previous, current){ ok, added, removed, changed }
  • summarize(schema, values) → printable string, secrets masked

opts.nodeEnv overrides NODE_ENV for the live-key check.

license

MIT