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

enwow

v0.1.0

Published

Cross-platform environment variables loader and validator with Standard Schema support

Readme

enwow

npm version npm downloads bundle License

Cross-platform environment variables loader and validator with Standard Schema support.

Features

  • 🚀 Cross-platform - Works on Node.js, Bun, and Deno
  • Standard Schema - Compatible with Zod, Valibot, ArkType, and more
  • 📁 .env file loading - With proper file priority support
  • 🔌 Pluggable sources - Load env from JSON files, CLI commands, secret managers, or any custom source
  • 🔒 Type-safe - Full TypeScript support with type inference
  • 🪶 Lightweight - Minimal dependencies

Installation

npm install enwow
# or
pnpm add enwow
# or
yarn add enwow

You'll also need a schema library that supports Standard Schema:

npm install zod
# or
npm install valibot
# or any other Standard Schema compatible library

Quick Start

Basic Usage

import { Env } from 'enwow'
import { z } from 'zod'

// Define your schema
const env = await Env.create({
  PORT: z.string().transform(Number).default('3000'),
  HOST: z.string().default('localhost'),
  DATABASE_URL: z.string().url(),
  DEBUG: z.string().optional(),
})

// Type-safe access
env.get('PORT') // number
env.get('HOST') // string
env.get('DATABASE_URL') // string
env.get('DEBUG') // string | undefined

With .env Files

import { Env } from 'enwow'
import { z } from 'zod'

const env = await Env.create(new URL('./', import.meta.url), {
  PORT: z.string().transform(Number).default('3000'),
  HOST: z.string().default('localhost'),
})

// Values from .env files are loaded and validated

File Loading Priority

Files are loaded in the following order (highest priority first):

| Priority | File Name | Environment | Notes | |----------|-----------|-------------|-------| | 1st | .env.[NODE_ENV].local | Current environment | Loaded when NODE_ENV is set | | 2nd | .env.local | All | Not loaded in test environment | | 3rd | .env.[NODE_ENV] | Current environment | Loaded when NODE_ENV is set | | 4th | .env | All | Always loaded |

process.env always has the highest priority and will override values from any file.

API

Env.create(schema, options?)

Create a new Env instance without loading .env files.

const env = await Env.create({
  PORT: z.string().transform(Number),
})

Env.create(path, schema, options?)

Create a new Env instance and load .env files from the specified directory.

const env = await Env.create(new URL('./', import.meta.url), {
  PORT: z.string().transform(Number),
})

Options

interface EnvCreateOptions {
  // Ignore existing process.env values
  ignoreProcessEnv?: boolean

  // Override NODE_ENV for file loading
  nodeEnv?: string

  // Custom environment variables source
  envSource?: Record<string, string | undefined>

  // Custom source adapters (cannot be used with path argument)
  sources?: EnvSourceAdapter[]
}

env.get(key)

Get a validated environment variable value.

const port = env.get('PORT') // Type: number

env.all()

Get all validated environment variables as an object.

const all = env.all() // Type: { PORT: number, HOST: string, ... }

env.has(key)

Check if a variable is defined.

if (env.has('DEBUG')) {
  // ...
}

Error Handling

When validation fails, an EnvValidationError is thrown:

import { EnvValidationError } from 'enwow'

try {
  const env = await Env.create({
    REQUIRED_VAR: z.string(),
  })
}
catch (error) {
  if (error instanceof EnvValidationError) {
    console.log('Validation failed:')
    for (const issue of error.issues) {
      console.log(`  ${issue.path}: ${issue.message}`)
    }
  }
}

Sources

By default, enwow loads environment variables from .env files and process.env. With source adapters, you can load from any source — JSON files, CLI commands, secret managers, or custom providers.

import { Env } from 'enwow'
import { fromFiles, fromJSON, fromObject, fromProcessEnv } from 'enwow/adapters'

Sources are merged left-to-right: later sources override earlier ones.

Built-in Adapters

| Adapter | Description | |---------|-------------| | fromFiles({ directory, ...options }) | Load from .env files (same as the default behavior) | | fromProcessEnv() | Read from process.env (cross-platform) | | fromJSON({ path }) | Read from a JSON file with flat key-value structure | | fromObject({ env }) | Use a static object (useful for testing and defaults) |

Example: Multiple Sources

import { Env } from 'enwow'
import { fromFiles, fromJSON, fromProcessEnv } from 'enwow/adapters'
import { z } from 'zod'

const env = await Env.create({
  PORT: z.string().transform(Number).default('3000'),
  DATABASE_URL: z.string().url(),
  API_SECRET: z.string(),
}, {
  sources: [
    fromFiles({ directory: new URL('./', import.meta.url) }), // lowest priority
    fromJSON({ path: './config/env.json' }),
    fromProcessEnv(), // highest priority
  ],
})

Custom Adapter

Use defineSourceAdapter to create a type-safe adapter factory:

import { defineSourceAdapter, fromFiles, fromProcessEnv } from 'enwow/adapters'

interface VaultOptions {
  url: string
  token: string
}

const vault = defineSourceAdapter<VaultOptions>((opts) => {
  return {
    name: 'vault',
    async load() {
      const response = await fetch(opts.url, {
        headers: { 'X-Vault-Token': opts.token },
      })
      const { data } = await response.json()
      return data.data
    },
  }
})

const env = await Env.create(schema, {
  sources: [
    fromFiles({ directory: new URL('./', import.meta.url) }),
    vault({ url: 'https://vault.example.com/v1/secret/data/myapp', token: process.env.VAULT_TOKEN! }),
    fromProcessEnv(),
  ],
})

Note: The sources option cannot be used together with the path argument in Env.create(path, schema). Use fromFiles() adapter instead.

Advanced Usage

With Valibot

import { Env } from 'enwow'
import * as v from 'valibot'

const env = await Env.create({
  PORT: v.pipe(v.string(), v.transform(Number), v.minValue(1), v.maxValue(65535)),
  HOST: v.optional(v.string(), 'localhost'),
})

With ArkType

import { type } from 'arktype'
import { Env } from 'enwow'

const env = await Env.create({
  PORT: type('string.integer').pipe(Number),
  HOST: type('string').default('localhost'),
})

Manual Validation

import { EnvValidator, parseEnv } from 'enwow'
import { z } from 'zod'

const validator = new EnvValidator({
  PORT: z.string().transform(Number),
})

const result = validator.validate(process.env)

Direct File Parsing

import { EnvLoader, EnvParser } from 'enwow'

const loader = new EnvLoader(new URL('./', import.meta.url))
const files = await loader.load()

for (const file of files) {
  const parser = new EnvParser(file.contents)
  const parsed = parser.parse()
  console.log(parsed)
}

Contribution

  • Clone this repository
  • Install the latest LTS version of Node.js
  • Enable Corepack using corepack enable
  • Install dependencies using pnpm install
  • Run tests using pnpm test

License

MIT License