> ## 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.

# Validator reference: str, num, bool, url, port

> Reference for next-safe-env validators. Covers str, num, bool, url, and port - including chainable methods, TypeScript type effects, and coercion behavior.

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

<ParamField body=".url()" type="this">
  Validates that the value parses as a valid URL using the `URL` constructor. Throws if `new URL(val)` throws.

  ```typescript theme={null}
  str().url()   // must be a valid URL
  ```
</ParamField>

<ParamField body=".min(n)" type="this">
  Requires the string length to be at least `n` characters (`val.length >= n`).

  ```typescript theme={null}
  str().min(8)   // at least 8 characters
  ```
</ParamField>

<ParamField body=".max(n)" type="this">
  Requires the string length to be no more than `n` characters (`val.length <= n`).

  ```typescript theme={null}
  str().max(256)   // at most 256 characters
  ```
</ParamField>

<ParamField body=".regex(r)" type="this">
  Requires the value to match the regular expression `r` (`r.test(val)` must be `true`).

  ```typescript theme={null}
  str().regex(/^[a-z_]+$/)   // lowercase letters and underscores only
  ```
</ParamField>

<ParamField body=".enum(values)" type="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.

  ```typescript theme={null}
  str().enum(['development', 'production', 'test'])
  // type: StringValidator<'development' | 'production' | 'test'>
  ```
</ParamField>

<ParamField body=".optional()" type="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.

  ```typescript theme={null}
  str().optional()
  // type: StringValidator<string | undefined>
  ```
</ParamField>

<ParamField body=".default(v)" type="StringValidator<string>">
  Sets a fallback value used when the variable is absent from `runtimeEnv`. The output type stays `string` (never `| undefined`).

  ```typescript theme={null}
  str().default('My App')
  // type: StringValidator<string>
  ```
</ParamField>

### Type effects

| Chain                                 | Output 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'`              |

<Note>
  `str()` always reads the raw string as-is. No type coercion is applied. Use `num()` or `bool()` when you need coercion.
</Note>

***

## `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

<ParamField body=".port()" type="this">
  Shorthand for `.int().min(1).max(65535)`. Requires the value to be an integer in the valid TCP port range.

  ```typescript theme={null}
  num().port()   // integer 1–65535
  ```
</ParamField>

<ParamField body=".int()" type="this">
  Requires the coerced number to be an integer (`Number.isInteger(val)` must be `true`). Rejects values like `"3.14"`.

  ```typescript theme={null}
  num().int()   // must be a whole number
  ```
</ParamField>

<ParamField body=".min(n)" type="this">
  Requires the coerced number to be greater than or equal to `n`.

  ```typescript theme={null}
  num().min(1)   // val >= 1
  ```
</ParamField>

<ParamField body=".max(n)" type="this">
  Requires the coerced number to be less than or equal to `n`.

  ```typescript theme={null}
  num().max(65535)   // val <= 65535
  ```
</ParamField>

<ParamField body=".optional()" type="NumberValidator<number | undefined>">
  Allows the variable to be absent. Returns `undefined` when the runtime value is `undefined` and no `.default()` is set.

  ```typescript theme={null}
  num().optional()
  // type: NumberValidator<number | undefined>
  ```
</ParamField>

<ParamField body=".default(v)" type="NumberValidator<number>">
  Sets a numeric fallback used when the variable is absent. The output type stays `number`.

  ```typescript theme={null}
  num().default(3000)
  // type: NumberValidator<number>
  ```
</ParamField>

<Note>
  `num()` uses `Number()` for coercion, not `parseInt`. The string `"3.14"` becomes `3.14`. Chain `.int()` to reject non-integers.
</Note>

***

## `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

| Result  | Accepted 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

<ParamField body=".optional()" type="BooleanValidator<boolean | undefined>">
  Allows the variable to be absent. Returns `undefined` when the runtime value is `undefined` and no `.default()` is set.

  ```typescript theme={null}
  bool().optional()
  // type: BooleanValidator<boolean | undefined>
  ```
</ParamField>

<ParamField body=".default(v)" type="BooleanValidator<boolean>">
  Sets a boolean fallback used when the variable is absent. The output type stays `boolean`.

  ```typescript theme={null}
  bool().default(false)
  // type: BooleanValidator<boolean>
  ```
</ParamField>

***

## Shorthands

Two factory functions wrap common validator chains so you do not have to repeat them:

<ParamField body="url()" type="StringValidator<string>">
  Equivalent to `str().url()`. Use when a variable must be a valid URL and no additional string constraints are needed.

  ```typescript theme={null}
  import { url } from 'next-safe-env'

  server: {
    DATABASE_URL: url(),             // same as str().url()
    API_ENDPOINT: url().optional(),  // valid URL or undefined
  }
  ```
</ParamField>

<ParamField body="port()" type="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.

  ```typescript theme={null}
  import { port } from 'next-safe-env'

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

***

## Chaining examples

Validators compose freely. Methods can be chained in any order that makes logical sense for your constraint.

```typescript theme={null}
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
```

<Tip>
  `.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.
</Tip>
