Skip to main content

Documentation Index

Fetch the complete documentation index at: https://next-safe-env.dev/llms.txt

Use this file to discover all available pages before exploring further.

next-safe-env is a zero-dependency library that validates and types your environment variables at startup. You define a schema once - server vars, client vars, their types, and any constraints - and the library either hands you a fully-typed, frozen object or crashes loudly with every problem listed, before your app serves a single request.

The problem with process.env

In every TypeScript project, process.env.X is always string | undefined. There is no autocomplete, no type coercion, and nothing that stops you from reaching a missing or malformed variable deep inside a request handler. The standard workaround is hand-written guard code repeated across every file that needs an env var:
// Without next-safe-env - manual guards scattered across your codebase
const DATABASE_URL = process.env.DATABASE_URL
if (!DATABASE_URL) throw new Error('Missing DATABASE_URL')

const PORT = parseInt(process.env.PORT ?? '3000', 10)
if (isNaN(PORT)) throw new Error('PORT must be a number')
This approach fails in compounding ways: missing vars are discovered mid-request instead of at startup, there is no single place to audit what your app needs to run, and nothing prevents you from reading a server-only secret in a client component where it silently becomes undefined in the browser. next-safe-env replaces all of that with a single function call:
// With next-safe-env - one schema, full types, startup crash on any failure
import { createEnv, str, url, port, bool } from 'next-safe-env'

export const env = createEnv({
  server: {
    DATABASE_URL: url(),
    PORT:         port().default(3000),
    NODE_ENV:     str().enum(['development', 'production', 'test']),
  },
  client: {
    NEXT_PUBLIC_APP_NAME:     str().default('My App'),
    NEXT_PUBLIC_ENABLE_DEBUG: bool().default(false),
  },
  runtimeEnv: {
    DATABASE_URL:             process.env.DATABASE_URL,
    PORT:                     process.env.PORT,
    NODE_ENV:                 process.env.NODE_ENV,
    NEXT_PUBLIC_APP_NAME:     process.env.NEXT_PUBLIC_APP_NAME,
    NEXT_PUBLIC_ENABLE_DEBUG: process.env.NEXT_PUBLIC_ENABLE_DEBUG,
  },
})

// env.DATABASE_URL  → string       (not string | undefined)
// env.PORT          → number       (coerced from string, not string)
// env.NODE_ENV      → 'development' | 'production' | 'test'

Key features

Startup crash, never runtime crash

Every variable is validated synchronously at module load time. If anything is missing or malformed, the process exits with a readable error listing every problem at once.

Full TypeScript inference

The return type of createEnv() is fully inferred from your schema. No separate type definitions to maintain. Add a field and it appears everywhere automatically.

Server/client split

Server vars and client vars live in separate schema keys. The nextjs adapter enforces the NEXT_PUBLIC_ prefix and strips server vars from the browser bundle at runtime.

Zero dependencies

No Zod, no dotenv, no peer deps. All validation logic ships in under 5 kB gzipped. Zod interop is available if your project already uses it - but it is never required.

Automatic type coercion

Built-in helpers like num() and bool() automatically convert string environment variables to their correct types so "3000" becomes 3000 and "true" becomes true, without any manual parsing.

Multi-runtime support

Works in Next.js App Router, plain Node.js, Vercel Edge Runtime, Next.js Middleware, and Vite. The correct adapter is auto-detected from the runtime environment.

How it compares

The table below uses data from the project README to compare next-safe-env against the most common alternatives.
Featurenext-safe-envt3-envenvaliddotenv + Zod
Zero dependencies
Next.js App Router supportPartial
Server/client TypeScript splitManual
Edge Runtime adapter
Fluent validator APISchema-basedCustomSchema-based
Pretty error outputPartialManual
Bundle size< 5 kB~50 kB+~10 kB~50 kB+
Auto-enforce NEXT_PUBLIC_ prefixManual
Zod interopOptionalRequiredRequired
ClientEnv<T> server-only brandingPartialManual
Vite adapterManual
If your project already uses Zod and you want schema reuse, t3-env integrates tightly with it. next-safe-env is the right choice when you want the full feature set - typed vars, server/client splitting, Edge Runtime support, and pretty error output - without adding any runtime dependencies.

Requirements

  • Node.js 18 or later
  • TypeScript 5.x
  • No runtime dependencies
next-safe-env validates what is already in process.env. It does not load .env files. Use Next.js’s built-in .env support or dotenv to load your files first, then let next-safe-env validate and type the result.

Next step

Quick Start

Install next-safe-env and define your first typed environment schema in under 5 minutes.