Type-safe environment variables. Loads .env files, validates with Zod/Valibot/ArkType, auto-coerces types. Drop-in dotenv replacement.
process.envisstring | undefined, so you lose types immediately.- Missing or malformed variables fail at runtime, often far away from startup.
- Client bundles can accidentally expose server secrets if env handling is ad hoc.
npm install envtrue zodpnpm add envtrue zodyarn add envtrue zodimport { createEnv } from "envtrue";
import { z } from "zod";
const env = createEnv({
server: {
DATABASE_URL: z.string().url(),
PORT: z.number(), // auto-coerced from "3000" → 3000
API_KEY: z.string().min(1),
},
client: {
API_BASE: z.string().url(),
},
clientPrefix: "NEXT_PUBLIC_"
});
const db: string = env.DATABASE_URL; // typed as string
await connect(db, { port: env.PORT }); // typed as number
fetch(env.API_BASE);| Feature | envtrue |
t3-env |
|---|---|---|
Loads .env files for you |
✅ | ❌ |
Auto-coerces z.number(), z.boolean(), z.array() |
✅ | ❌ |
No runtimeEnv boilerplate |
✅ | ❌ |
| Framework-agnostic core | ✅ |
envtrue is optimized for the common case: read .env, merge with runtime env, coerce strings into the right primitives, validate once, return typed values. No extra runtime mapping step.
The usual Zod setup is a small pile of repeated glue:
- Load
.envyourself - Merge sources manually
- Remember to coerce strings before validation
- Split public and private variables by convention
- Build readable startup errors yourself
envtrue keeps the schema but removes the glue. It auto-loads .env and .env.local, auto-coerces string inputs, separates client variables by prefix, and throws one formatted error with every invalid variable listed at once.
| Adapter | Import | Notes |
|---|---|---|
| Next.js | import { createNextEnv } from "envtrue/nextjs" |
Uses NEXT_PUBLIC_, skips server validation in browser bundles, skips validation during Next build phases when needed |
| Vite | import { createViteEnv } from "envtrue/vite" |
Uses VITE_, works with import.meta.env or process.env |
| Hono | import { createHonoEnv } from "envtrue/hono" |
Server-only, supports explicit env bindings such as Cloudflare Workers / c.env |
createEnv({
server,
client,
clientPrefix,
envFiles,
cwd,
env,
skipValidation,
onError
})| Option | Type | Default | Description |
|---|---|---|---|
server |
SchemaShape |
{} |
Server-only environment schema |
client |
SchemaShape |
{} |
Client-safe environment schema |
clientPrefix |
string |
"NEXT_PUBLIC_" |
Prefix required for client variables |
envFiles |
string | string[] |
[".env", ".env.local"] |
.env files to load, in merge order |
cwd |
string |
process.cwd() |
Base directory used to resolve envFiles |
env |
Record<string, string | undefined> |
process.env |
Explicit runtime env source override |
skipValidation |
boolean |
false |
Skip schema validation and return coerced raw values |
onError |
(errors: EnvError[]) => void |
throws formatted error | Hook for custom error handling |
- Load
.envfiles from disk. - Merge loaded values with runtime env. Runtime env wins.
- Coerce string values before validation.
- Validate server and client schemas.
- Throw one aggregated error if anything is invalid.
- Return a frozen typed object.
- Zod raw shapes
- Standard Schema compatible shapes (Valibot, ArkType)
ArkType is supported through Standard Schema compatibility, but is not currently covered by the test suite.
- Monorepo support
- Encrypted
.envsupport withdotenvxcompatibility - VS Code extension for
.envautocomplete and intellisense
MIT