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.

Validators are chainable builder objects that describe the type, constraints, and fallback behavior of a single environment variable. You compose them inline inside your server and client schemas - each method returns the same validator instance so calls can be chained freely. Every validator implements the FieldValidator<T> interface, where T is the TypeScript output type the chain produces.

str()

str() reads the raw string value from process.env with no coercion. It returns a StringValidator<string>.

Chainable methods

.url()
this
Validates that the value parses as a valid URL using the URL constructor. Throws if new URL(val) throws.
str().url()   // must be a valid URL
.min(n)
this
Requires the string length to be at least n characters (val.length >= n).
str().min(8)   // at least 8 characters
.max(n)
this
Requires the string length to be no more than n characters (val.length <= n).
str().max(256)   // at most 256 characters
.regex(r)
this
Requires the value to match the regular expression r (r.test(val) must be true).
str().regex(/^[a-z_]+$/)   // lowercase letters and underscores only
.enum(values)
StringValidator<E | Exclude<T, string>>
Requires the value to be one of the strings in values. Narrows the output type to the literal union E. When chained after .optional(), the undefined variant is preserved in the narrowed type.
str().enum(['development', 'production', 'test'])
// type: StringValidator<'development' | 'production' | 'test'>
.optional()
StringValidator<string | undefined>
Allows the variable to be absent. When the runtime value is undefined and no .default() is set, the validator returns undefined instead of throwing.
str().optional()
// type: StringValidator<string | undefined>
.default(v)
StringValidator<string>
Sets a fallback value used when the variable is absent from runtimeEnv. The output type stays string (never | undefined).
str().default('My App')
// type: StringValidator<string>

Type effects

ChainOutput type
str()string
str().optional()string | undefined
str().default('x')string
str().enum(['a', 'b'])'a' | 'b'
str().optional().enum(['a', 'b'])'a' | 'b' | undefined
str().enum(['a', 'b']).default('a')'a' | 'b'
str() always reads the raw string as-is. No type coercion is applied. Use num() or bool() when you need coercion.

num()

num() coerces the raw string to a number using Number(rawValue). If the result is NaN, validation fails immediately and no chained rules run. It returns a NumberValidator<number>.

Chainable methods

.port()
this
Shorthand for .int().min(1).max(65535). Requires the value to be an integer in the valid TCP port range.
num().port()   // integer 1–65535
.int()
this
Requires the coerced number to be an integer (Number.isInteger(val) must be true). Rejects values like "3.14".
num().int()   // must be a whole number
.min(n)
this
Requires the coerced number to be greater than or equal to n.
num().min(1)   // val >= 1
.max(n)
this
Requires the coerced number to be less than or equal to n.
num().max(65535)   // val <= 65535
.optional()
NumberValidator<number | undefined>
Allows the variable to be absent. Returns undefined when the runtime value is undefined and no .default() is set.
num().optional()
// type: NumberValidator<number | undefined>
.default(v)
NumberValidator<number>
Sets a numeric fallback used when the variable is absent. The output type stays number.
num().default(3000)
// type: NumberValidator<number>
num() uses Number() for coercion, not parseInt. The string "3.14" becomes 3.14. Chain .int() to reject non-integers.

bool()

bool() coerces the raw string to a boolean using a case-insensitive lookup against a fixed set of accepted strings. It returns a BooleanValidator<boolean>.

Accepted values

ResultAccepted strings
true"true", "1", "yes", "on"
false"false", "0", "no", "off"
The comparison is case-insensitive - "TRUE", "True", and "true" are all accepted. Any string outside these eight values causes validation to fail.

Chainable methods

.optional()
BooleanValidator<boolean | undefined>
Allows the variable to be absent. Returns undefined when the runtime value is undefined and no .default() is set.
bool().optional()
// type: BooleanValidator<boolean | undefined>
.default(v)
BooleanValidator<boolean>
Sets a boolean fallback used when the variable is absent. The output type stays boolean.
bool().default(false)
// type: BooleanValidator<boolean>

Shorthands

Two factory functions wrap common validator chains so you do not have to repeat them:
url()
StringValidator<string>
Equivalent to str().url(). Use when a variable must be a valid URL and no additional string constraints are needed.
import { url } from 'next-safe-env'

server: {
  DATABASE_URL: url(),             // same as str().url()
  API_ENDPOINT: url().optional(),  // valid URL or undefined
}
port()
NumberValidator<number>
Equivalent to num().port(), which expands to num().int().min(1).max(65535). Use for any variable that holds a TCP port number.
import { port } from 'next-safe-env'

server: {
  PORT:      port().default(3000),  // integer 1–65535, defaults to 3000
  SMTP_PORT: port().default(587),
}

Chaining examples

Validators compose freely. Methods can be chained in any order that makes logical sense for your constraint.
import { str, num, bool, url, port } from 'next-safe-env'

// String constraints
str().min(8).max(64)
str().min(32)                                           // secret key, at least 32 chars
str().regex(/^[a-z_]+$/).default('default_value')
str().enum(['debug', 'info', 'warn', 'error']).default('info')
str().url().optional()                                  // valid URL or omitted

// Number constraints
num().int().min(1).max(100).default(10)
num().min(0).max(1)                                     // float between 0 and 1
port().default(3000)                                    // shorthand for num().int().min(1).max(65535)

// Boolean with defaults
bool().default(true)
bool().default(false)
bool().optional()

// Optional with enum
str().optional().enum(['development', 'staging', 'production'])
// type: 'development' | 'staging' | 'production' | undefined
.optional() and .default() can be combined. When both are set, .default() takes priority if the variable is missing - the value is never undefined. Use .optional() alone when absence is a valid and meaningful state.