An open API service indexing awesome lists of open source software.

https://github.com/mzeeshanwahid/next-safe-env

Typed, validated environment variables for Next.js and Node.js
https://github.com/mzeeshanwahid/next-safe-env

configuration dotenv edge-runtime env-validation environment-variables next-publix nextjs nodejs server-only type-safe typescript vite zero-dependency

Last synced: 7 days ago
JSON representation

Typed, validated environment variables for Next.js and Node.js

Awesome Lists containing this project

README

          


next-safe-env logo

next-safe-env


Typed, validated environment variables for Next.js and Node.js. Crash at startup, never at runtime.



npm version bundle size license tests zero dependencies TypeScript

---

## The Problem

Every Next.js and Node.js project has the same boilerplate:

```ts
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')
```

`process.env.X` is always `string | undefined` - no types, no autocomplete. Missing or malformed vars surface mid-request, not at startup. Nothing stops you from reading a server secret in a client component and getting a silent `undefined` in the browser. Every project re-writes the same validation logic with no single place to audit what the app needs to run.

`next-safe-env` fixes all of this with a single function call.

---

## Why `next-safe-env`?

| Feature | **next-safe-env** | t3-env | envalid | dotenv + Zod |
|---|:---:|:---:|:---:|:---:|
| Zero dependencies | ✅ | ❌ | ❌ | ❌ |
| Next.js App Router support | ✅ | Partial | ❌ | ❌ |
| Server/client TypeScript split | ✅ | ✅ | ❌ | Manual |
| Edge Runtime adapter | ✅ | ❌ | ❌ | ❌ |
| Fluent validator API | ✅ | Schema-based | Custom | Schema-based |
| Pretty error output | ✅ | Partial | ✅ | Manual |
| Bundle size | **< 5 kB** | ~50 kB+ | ~10 kB | ~50 kB+ |
| Auto-enforce `NEXT_PUBLIC_` prefix | ✅ | Manual | ❌ | ❌ |
| Zod interop | Optional ✅ | Required | ❌ | Required |
| `ClientEnv` server-only branding | ✅ | Partial | ❌ | Manual |
| Vite adapter | ✅ | ✅ | ❌ | Manual |
| CLI (`check` / `init`) | ✅ | ❌ | ❌ | ❌ |

If your project already uses a schema validation library, tools like `t3-env` or `envalid` integrate well with your existing setup. `next-safe-env` is for teams that want typed, validated env vars with no additional dependencies - the full feature set ships in under 5 kB.

---

## Requirements

- **Node.js** 18+
- **TypeScript** 5.x

No runtime dependencies.

---

## Installation

```bash
npm install next-safe-env
# or
pnpm add next-safe-env
# or
yarn add next-safe-env
```

> `next-safe-env` validates what is already in `process.env`. It does not load `.env` files. For that, use Next.js's built-in `.env` support or `dotenv`.

---

## Quick Start

```ts
// src/env.ts
import { createEnv, str, url, port, bool } from 'next-safe-env'

export const env = createEnv({
server: {
DATABASE_URL: url(), // must be a valid URL
PORT: port().default(3000), // coerced to number, defaults to 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,
},
})
```

```ts
// anywhere in your app
import { env } from '@/env'

env.DATABASE_URL // string
env.PORT // number - not string
env.NEXT_PUBLIC_APP_NAME // string
```

If any variable is missing or invalid, the app refuses to start and prints every problem at once:

```
[next-safe-env] Environment validation failed - 3 error(s):

✗ DATABASE_URL - Required. Expected a valid URL. Got: "postgres-localhost"
✗ JWT_SECRET - Too short. Must be ≥ 32 characters. Got length: 12
✗ SMTP_PORT - Invalid port. Must be 1–65535. Got: "99999"
```

---

## CLI

`next-safe-env` ships a zero-install CLI for validation and scaffolding.

### `check` — validate before you deploy

Imports your compiled env file in an isolated process and exits `0` if all vars are valid, `1` if any fail. Drop it into any CI pipeline to gate deployments:

```bash
# Auto-discovers src/env.js then dist/env.js
npx next-safe-env check

# Or point at a specific file
npx next-safe-env check ./dist/env.js
```

```
[next-safe-env] Checking src/env.js...

[next-safe-env] Environment validation failed — 2 error(s):

✗ DATABASE_URL — Expected valid URL. Got: "postgres-localhost"
✗ JWT_SECRET — Expected length >= 32. Got length: 12

[next-safe-env] ✗ Validation failed.
```

### `init` — generate `src/env.ts` and `.env.example`

An interactive scaffold that asks which variables your app needs, their types, defaults, and constraints — then writes a ready-to-use `env.ts` and a commented `.env.example`:

```bash
npx next-safe-env init

# Custom output path
npx next-safe-env init --output config/env.ts
```

The generated `.env.example` includes inline comments for every variable so new contributors know exactly what to fill in:

```dotenv
# DATABASE_URL — required valid URL
DATABASE_URL=

# PORT — required port number (1–65535)
# Default: 3000
PORT=3000

# NODE_ENV — required string
# Allowed values: development | production | test
NODE_ENV=
```

---

## Documentation

The full documentation is available at **[next-safe-env.dev](https://next-safe-env.dev)**.

### Guides

- [Getting Started](https://next-safe-env.dev/quickstart) - Install and validate your first env var in minutes
- [Next.js App Router](https://next-safe-env.dev/guides/nextjs) - Server/client splitting with automatic `NEXT_PUBLIC_` enforcement
- [Node.js](https://next-safe-env.dev/guides/nodejs) - Plain Node.js servers, APIs, and CLI scripts
- [Edge Runtime](https://next-safe-env.dev/guides/edge-runtime) - Vercel Edge Runtime and Next.js Middleware
- [Vite](https://next-safe-env.dev/guides/vite) - Non-Next.js React apps with `import.meta.env`
- [Zod Interop](https://next-safe-env.dev/guides/zod-interop) - Pass `z.object(...)` schemas directly, no rewrites needed
- [Testing](https://next-safe-env.dev/guides/testing) - Skip validation in test environments without removing your schema
- [CLI](https://next-safe-env.dev/guides/cli) - `check` and `init` commands for CI validation and interactive scaffolding

### API Reference

- [Validators](https://next-safe-env.dev/api/validators) - `str`, `num`, `bool`, `url`, `port` and their chainable rules
- [createEnv()](https://next-safe-env.dev/api/create-env) - Full reference for every configuration option
- [TypeScript Types](https://next-safe-env.dev/api/types) - `ServerOnly`, `ClientEnv`, and all exported types

### Concepts

- [Adapters](https://next-safe-env.dev/concepts/adapters) - How Next.js, Node.js, Edge Runtime, and Vite adapters work
- [Server & Client Split](https://next-safe-env.dev/concepts/server-client-split) - How env vars are separated and protected per runtime context
- [Error Handling](https://next-safe-env.dev/concepts/error-handling) - Validation errors, pretty output, and custom error handlers

---

`next-safe-env` was built because `process.env.X` should never be `string | undefined` in a typed codebase - and getting full validation, type inference, and Next.js adapter support shouldn't require adding new dependencies to do it.

MIT © 2026