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

@the-arj/env-types

v0.1.0

Published

Zero-schema TypeScript type generation and runtime validation from .env files. Auto-generates env.d.ts from .env.example — no schema duplication.

Readme

env-types

Zero-schema TypeScript types from your .env.example — auto-generated, no duplication.

# Add to .env.example once, get types everywhere
npx @the-arj/env-types generate
// process.env is now fully typed — no schema to write
process.env.DATABASE_URL   // string
process.env.PORT           // string
process.env.SENTRY_DSN     // string | undefined  (was empty in .env.example)
process.env.TYPO_HERE      // ✗ TypeScript error — doesn't exist

The Problem

Every other solution makes you write the schema yourself:

// t3-env, envalid, zod — you duplicate your .env:
const env = createEnv({
  server: {
    DATABASE_URL: z.string().url(),   // ← you already wrote this in .env.example
    PORT: z.coerce.number(),          // ← why write it twice?
  }
})

env-types reads .env.example and generates the types for you. No schema, no duplication.


Install

npm install -D @the-arj/env-types

Quick Start

1. Add to package.json scripts:

{
  "scripts": {
    "env:generate": "env-types generate",
    "env:validate": "env-types validate"
  }
}

2. Generate types:

npm run env:generate

This reads .env.example and writes env.d.ts:

// env.d.ts — auto-generated by env-types
declare namespace NodeJS {
  interface ProcessEnv {
    /** App config */
    NODE_ENV: string
    /** @type {number string} */
    PORT: string
    /** Database */
    DATABASE_URL: string
    /** @optional */
    SENTRY_DSN?: string
  }
}

3. Validate before deploy:

npm run env:validate
# ✓ All 4 required variables are set.
# — or —
# ✗ 2 missing variables:
#   • DATABASE_URL: Required variable "DATABASE_URL" is missing or empty
#   • SECRET_KEY: Required variable "SECRET_KEY" is missing or empty

CLI Reference

env-types generate

Generate env.d.ts from .env.example.

env-types generate
env-types generate --input .env --output src/env.d.ts
env-types generate --watch          # re-generate on file change
env-types generate --scaffold       # generate a loadEnv() schema instead

| Flag | Default | Description | |---|---|---| | --input | .env.example | Source .env file | | --output | env.d.ts | Output .d.ts file | | --watch | — | Watch and re-generate on change | | --scaffold | — | Output a loadEnv() schema instead of .d.ts |

env-types validate

Check that all required variables from .env.example are set in the current environment.

env-types validate
env-types validate --input .env.example

Exits with code 1 if any required variables are missing — safe to use in CI.


Library API

loadEnv(schema, source?)

Runtime-safe, typed env loading with coercion. Use when you want numbers/booleans instead of raw strings.

import { loadEnv } from '@the-arj/env-types'

const env = loadEnv({
  PORT:         { type: 'number' },
  NODE_ENV:     { type: 'string' },
  DEBUG:        { type: 'boolean', required: false, default: false },
  DATABASE_URL: { type: 'url' },
})

env.PORT    // number  ✓
env.DEBUG   // boolean ✓

Throws a consolidated error listing all missing/invalid variables at once.

Supported types

| Type | Input | Output | |---|---|---| | 'string' | any string | string | | 'number' | "3000" | 3000 | | 'boolean' | "true" / "false" | true / false | | 'url' | "https://..." | string (validated) | | 'json' | '{"a":1}' | unknown (parsed) |

parseEnvFile(content)

Parse a .env file string into structured entries.

import { parseEnvFile } from '@the-arj/env-types'

const entries = parseEnvFile(`
# Server port
PORT=3000
DATABASE_URL=postgres://localhost/db
OPTIONAL=
`)

// entries[0] → { key: 'PORT', rawValue: '3000', isOptional: false, inferredType: 'number', description: 'Server port' }

generateDts(entries, options?)

Generate a .d.ts string from parsed entries.

import { parseEnvFile, generateDts } from '@the-arj/env-types'
import { readFileSync, writeFileSync } from 'node:fs'

const content = readFileSync('.env.example', 'utf8')
const entries = parseEnvFile(content)
writeFileSync('env.d.ts', generateDts(entries))

validateAgainstEntries(entries, source?)

Validate a source object against parsed entries. Returns an array of ValidationError objects (empty = valid).

import { parseEnvFile, validateAgainstEntries } from '@the-arj/env-types'

const entries = parseEnvFile(readFileSync('.env.example', 'utf8'))
const errors = validateAgainstEntries(entries, process.env)

if (errors.length > 0) {
  for (const e of errors) console.error(`Missing: ${e.key}`)
  process.exit(1)
}

Type Inference Rules

| Value in .env.example | inferredType | Optional? | |---|---|---| | PORT=3000 | number | no | | DEBUG=true | boolean | no | | URL=https://api.example.com | url | no | | CONFIG={"a":1} | json | no | | NODE_ENV=development | string | no | | OPTIONAL= | string | yes |

All ProcessEnv values are string — type hints are informational JSDoc only. Use loadEnv() for actual coercion.


Recommended Workflow

.env.example  →  env-types generate  →  env.d.ts  →  TypeScript knows your vars
                 env-types validate  →  CI fails fast on missing vars

Add to your postinstall or CI setup step:

{
  "scripts": {
    "postinstall": "env-types generate"
  }
}

License

MIT © The-ARJ