Packages

@thexjs/env

Type-safe environment variable validation for x apps. Define a schema once, get parsed and typed values back, and fail fast with a clear error if something is missing or malformed.

terminal
bun add @thexjs/env

Quick start

env.ts
import { createEnv, str, num, bool, oneOf, url } from "@thexjs/env";export const env = createEnv({  server: {    DATABASE_URL: url(),    PORT: num(),    NODE_ENV: oneOf(["development", "production", "test"]),  },  client: {    NEXT_PUBLIC_API_URL: url(),  },  clientPrefix: "NEXT_PUBLIC_",  runtimeEnv: process.env,});env.DATABASE_URL; // string, validated as a URLenv.PORT;         // numberenv.NODE_ENV;     // "development" | "production" | "test"

If any variable is missing or fails validation, createEnv throws a single error listing every failure:

validation error
Environment validation failed:  server.DATABASE_URL: Expected a valid URL, got "not-a-url"  server.PORT: Expected a number, got undefined

Validators

built-in validators
Validator              Accepts                          Notesstr()                  any non-undefined stringnum()                  numeric strings                  rejects NaNbool()                 "true"/"1"  true, "false"/"0"  falseoneOf([...values])     one of the given string literals   narrows return typeurl()                  string parseable by new URL(...)

Custom validators

Each validator is { parse(input: string | undefined): T } — write your own for anything not covered:

custom validator
import type { EnvValidator } from "@thexjs/env";function json<T>(): EnvValidator<T> {  return {    parse(input) {      if (input === undefined) throw new Error("Expected JSON, got undefined");      return JSON.parse(input) as T;    },  };}

client / clientPrefix

The client schema is for variables safe to expose to the browser. clientPrefix enforces that every client key starts with that prefix (e.g. NEXT_PUBLIC_, PUBLIC_) — a key that does not match fails validation, so you cannot accidentally leak a server-only variable through the client schema.

Notes

  • Every field is currently required — no built-in optional() or default(). For optional vars, read from process.env directly or write a validator with a fallback.
  • runtimeEnv is passed explicitly so this works on Bun, in bundlers that inline process.env.* at build time, or in tests with a mocked env object.