Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

schema-env

devvictrix1.3kMIT2.1.6TypeScript support: included

Type-safe environment variable validation for Node.js using Zod schemas or custom adapters. Load .env files, expand variables, fetch async secrets, and validate process.env at startup.

env, environment, variables, config, configuration, settings, validate, validation, schema, typescript, type-safe, zod, joi, yup, adapter, extensible, dotenv, dotenv-expand, node, nodejs, startup, process.env, security, secure, secrets, secrets-management, async, asynchronous, ai, ai-assisted, ai-developed, ai-enhanced, llm, gpt, ai-collaborator, automated-development

readme

schema-env: Your App's Smart Instruction Checker!

npm version Downloads per month License: MIT Test Coverage TypeScript Support Developed with AI Assistance

Ever tried to build a LEGO set without the right pieces or with confusing instructions? Your app can feel the same way if its "environment variables" (special settings it needs to run) are wrong!

schema-env is like a super-helpful assistant that checks these settings for your Node.js app before it even starts. It makes sure everything is A-OK, so your app can run smoothly and reliably.


TL;DR (Too Long; Didn't Read)

schema-env makes your app safer by checking its settings (like API keys, port numbers) against a rulebook (your Zod schema or custom adapter) right at the start. It can read settings from .env files, special files for development/production, and even secret vaults! If something's wrong, it tells you immediately.


DX Highlights (Developer Experience Wins!)

  • Peace of Mind: No more "Oops, I forgot that setting!" errors in production.
  • 📖 Clear Rules: Define exactly what your app needs, in one place.
  • 🤝 Team-Friendly: Everyone knows what settings are required.
  • 🤖 Async & Flexible: Works with modern setups, including fetching secrets.
  • 🧩 Use Your Favorite Tools: Zod is built-in, but you can plug in Joi, Yup, etc.
  • 💡 Smart & Simple API: Easy to get started, powerful when you need it.

What's an "Environment Variable"? And Why Check Them?

Think of environment variables as little notes you give your app:

  • PORT=3000 (Tells your app which door to use for web traffic)
  • API_KEY=supersecret123 (A secret password to talk to another service)
  • NODE_ENV=development (Tells your app if it's in "practice mode" or "live mode")

If these notes are missing, misspelled, or have the wrong kind of info (like text where a number should be), your app might get confused, crash, or even worse, do something unexpected!

schema-env helps by:

  1. Reading a "Rulebook" (Schema): You tell schema-env what notes your app expects and what they should look like.
  2. Checking the "Notes" (.env files & system): It looks at the notes you've provided.
  3. Giving a Thumbs Up or Down: If all notes match the rulebook, great! If not, it stops your app and tells you exactly what's wrong.

This makes your app:

  • 👍 More Reliable: Fewer surprise crashes.
  • 🔒 More Secure: Helps ensure secret keys are present and correctly formatted.
  • 🛠️ Easier to Debug: Find configuration problems instantly.

Features - What Can This Assistant Do?

  • 🔍 Checks Your Settings (Validation): Makes sure settings are the right type (text, number, URL, etc.) and follow your rules. Uses the popular Zod library by default, but you can bring your own!
  • 📄 Reads .env Files: Automatically loads settings from .env files – a common way to store them.
  • 🌳 Understands Different "Moods" (Environments): Can load different settings for "development" (.env.development), "production" (.env.production), etc.
  • Handles Multiple Instruction Sheets: You can have a base set of settings and then override them with local ones.
  • 🔗 Smart Links in Settings (Variable Expansion): Lets one setting use the value of another (e.g., FULL_URL = ${BASE_URL}/api).
  • 🤫 Fetches Secret Settings (Asynchronous): Can get super-secret settings from secure vaults before checking everything.
  • 🥇 Knows Who's Boss (Clear Precedence): If a setting is defined in multiple places, schema-env knows which one to use.
  • 🛡️ Doesn't Change Global Settings: It won't mess with your computer's main settings.
  • 🗣️ Clear Error Messages: Tells you all the problems at once, not one by one.
  • 🤖 AI-Powered Helper: This library was built with the help of an AI assistant!

Let's Get Started! (Basic Magic)

1. Install schema-env and zod (our default rulebook maker):

npm install schema-env zod
# or
yarn add schema-env zod

2. Create Your Rulebook (envSchema.ts): Tell schema-env what settings your app needs.

// envSchema.ts
import { z } from "zod"; // Zod helps us make the rules!

export const envSchema = z.object({
  // Rule 1: NODE_ENV should be "development" or "production". Default to "development".
  NODE_ENV: z.enum(["development", "production"]).default("development"),

  // Rule 2: PORT should be a number. If not given, use 3000.
  PORT: z.coerce.number().default(3000),

  // Rule 3: GREETING_MESSAGE must be text, and you *must* provide it!
  GREETING_MESSAGE: z.string().min(1, "Oops! You forgot the greeting message!"),
});

// This creates a TypeScript type for our validated settings - super handy!
export type Env = z.infer<typeof envSchema>;

3. Write Down Your App's Settings (.env file): Create a file named .env in the main folder of your project.

# .env
GREETING_MESSAGE="Hello from schema-env!"
PORT="8080"

(Notice we didn't put `NODEENV` here? Our rulebook says it defaults to "development"!)_

4. Tell schema-env to Check Everything (in your app's main file, like index.ts or server.ts):

// index.ts
import { createEnv } from "schema-env";
import { envSchema, Env } from "./envSchema.js"; // Use .js for modern JavaScript modules

let settings: Env; // This will hold our correct settings

try {
  // Time for the magic check!
  settings = createEnv({ schema: envSchema });
  console.log("✅ Hooray! All settings are correct!");
} catch (error) {
  console.error("❌ Oh no! Something's wrong with the settings.");
  // schema-env already printed the detailed error messages for us!
  process.exit(1); // Stop the app, because settings are bad.
}

// Now you can safely use your settings!
console.log(`The app says: ${settings.GREETING_MESSAGE}`);
console.log(`Running in ${settings.NODE_ENV} mode on port ${settings.PORT}.`);

// Go ahead and start your amazing app!
// startMyApp(settings);

If you run this and your .env file is missing GREETING_MESSAGE or PORT is not a number, schema-env will tell you!

Doing More Cool Things!

Different Settings for Different "Moods" (e.g., Development vs. Production)

If you have a setting NODE_ENV (like in our example), schema-env is extra smart:

  • If NODE_ENV=development, it will also try to load settings from a file named .env.development.
  • If NODE_ENV=production, it will look for .env.production.

Settings in these specific files will override settings from the main .env file.

Settings That Depend on Other Settings (Variable Expansion)

Want API_URL to be ${HOSTNAME}/api? Easy! First, tell schema-env you want to do this:

settings = createEnv({
  schema: envSchema, // Your usual rulebook
  expandVariables: true, // Set this to true!
});

Then, in your .env file:

HOSTNAME="http://mycoolsite.com"
API_URL="${HOSTNAME}/v1/data"

schema-env will figure out API_URL should be http://mycoolsite.com/v1/data.

Using Multiple .env Files

Sometimes you want a base set of settings and then some local ones that only you use.

settings = createEnv({
  schema: envSchema,
  dotEnvPath: [".env.defaults", ".env.local"], // Checks .env.defaults, then .env.local
});

Later files in the list override earlier ones. And the "mood" specific file (like .env.development) still gets checked after all of these!

For the Pros: Super Secret Settings & Your Own Rules!

Getting Secrets from a Secure Vault (Async Magic with createEnvAsync)

Some settings, like database passwords, are too secret for .env files. You might keep them in a "secrets manager" (like AWS Secrets Manager, HashiCorp Vault, etc.). schema-env can fetch these before it checks all your rules!

// mySecretFetcher.ts
import type { SecretSourceFunction } from "schema-env";

export const fetchMyDatabasePassword: SecretSourceFunction = async () => {
  console.log("🤫 Asking the secret vault for the DB password...");
  // In real life, you'd use a library here to talk to your secrets manager.
  // We'll pretend it takes a moment:
  await new Promise((resolve) => setTimeout(resolve, 50));
  return {
    DB_PASSWORD: "ultra-secret-password-from-vault",
  };
};

Then, in your app:

// index.ts
import { createEnvAsync } from "schema-env"; // Note: createEnvAsync!
import { envSchema, Env } from "./envSchema.js"; // Your schema needs to expect DB_PASSWORD
import { fetchMyDatabasePassword } from "./mySecretFetcher.js";

async function startAppSafely() {
  let settings: Env;
  try {
    settings = await createEnvAsync({
      // await is important here!
      schema: envSchema,
      secretsSources: [fetchMyDatabasePassword], // Add your secret fetchers here
    });
    console.log("✅ Secrets fetched and all settings are correct!");
    // console.log(`DB Password's first letter: ${settings.DB_PASSWORD[0]}`); // Be careful logging secrets!
  } catch (error) {
    console.error(
      "❌ Oh no! Something went wrong with settings (maybe secrets?)."
    );
    process.exit(1);
  }
  // startMyApp(settings);
}

startAppSafely();

Don't Like Zod? Bring Your Own Rulebook Checker! (Custom Adapters)

If your team already uses another library like Joi or Yup to define rules, you can tell schema-env to use that instead of Zod!

You'll need to create a small "adapter" that teaches schema-env how to talk to your chosen library. This involves implementing the ValidatorAdapter interface provided by schema-env.

<summary>Advanced: More on Custom Validation Adapters</summary>

To use a custom validation library (like Joi, Yup, or your own):

  1. Define your environment type and schema using your chosen library.
  2. Implement the ValidatorAdapter<TResult> interface from schema-env. This adapter will:
    • Take the merged environment data as input.
    • Use your chosen library to validate this data.
    • Return a ValidationResult<TResult> object, which tells schema-env if validation succeeded (and the typed data) or failed (with standardized error details).
  3. Pass an instance of your adapter to createEnv or createEnvAsync using the validator option. You'll also need to provide the expected result type as a generic argument (e.g., createEnv<undefined, MyCustomEnvType>({ validator: myAdapter })).

For a complete, runnable example showing how to create and use a custom adapter with Joi, please see the examples/custom-adapter-joi/ directory in this repository. It includes: _ A Joi schema definition (env.joi.ts). _ The Joi adapter implementation (joi-adapter.ts). * An example of how to use it (index.ts).

This demonstrates the flexibility of schema-env in integrating with various validation workflows.

Who Wins? The Order of Settings (Precedence)

If a setting is defined in multiple places, here's who wins (highest number wins):

For createEnv (the simpler one):

  1. Default values in your rulebook (schema).
  2. Values from your .env file(s) (and expanded if you turned that on).
  3. Values from your computer's actual environment (these are like global settings).

For createEnvAsync (the one for secrets):

  1. Default values in your rulebook (schema).
  2. Values from your .env file(s) (expanded if on).
  3. Values fetched from your secretsSources (the secret vaults).
  4. Values from your computer's actual environment.

Quick Look at the Main Tools (API Reference)

createEnv(options)

  • Checks settings right away.
  • If something is wrong, it stops and tells you (throws an error).
  • Returns your perfectly validated settings.

async createEnvAsync(options)

  • Can fetch secrets from vaults first.
  • Then checks all settings.
  • If something is wrong, it tells you by rejecting its Promise.
  • If all good, its Promise gives you the validated settings.

Key Options (for both tools):

  • schema: Your Zod rulebook. (Use this OR validator)
  • validator: Your custom rulebook checker. (Use this OR schema)
  • dotEnvPath: Which .env file(s) to read. (e.g., './.env.custom' or ['./.env.base', './.env.local']). Defaults to just ./.env. Can be false to load no .env files.
  • expandVariables: true or false to turn on smart links in .env files. (Defaults to false)
  • secretsSources: (Only for createEnvAsync) A list of functions that go fetch your secrets.

Want to Help or Have Ideas? (Contributing)

That's awesome! We'd love your help.

  • New ideas, bug reports, and improvements are always welcome. Feel free to open an issue or a pull request.

License

MIT © devvictrix (AI Assisted)