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

# TypeScript types exported by next-safe-env

> Reference for types exported by next-safe-env: ServerOnly, ClientEnv, InferEnv, EnvConfig, ValidationFailure, ValidationStats, FieldValidator, and Adapter.

`next-safe-env` exports a set of TypeScript types you can use to annotate functions, derive types from your schema, or build wrapper utilities. All types are re-exported from the package root, so you can import them directly from `next-safe-env`. None of these types have a runtime representation - they exist solely in the TypeScript type system.

***

## `ServerOnly<T>`

`ServerOnly<T>` brands a type `T` with a unique symbol that marks it as originating from the `server` schema. Every value in the returned env object that comes from a `server` key carries this brand, making its origin visible in IDE tooltips.

```typescript theme={null}
declare const SERVER_ONLY_BRAND: unique symbol

type ServerOnly<T> = T & { readonly [SERVER_ONLY_BRAND]: void }
```

Because TypeScript uses structural typing, `ServerOnly<T>` is assignment-compatible with `T`. It does not produce a compile error by itself. To get a hard compile error when client components import server vars, add `import 'server-only'` at the top of your `env.ts` file.

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

// Annotate a function that only accepts server-side values
function connectDB(url: ServerOnly<string>) { /* ... */ }
```

***

## `ClientEnv<TEnv>`

`ClientEnv<TEnv>` strips every `ServerOnly`-branded key from an env type, leaving only the client-safe keys. Use it to constrain functions or components that must not access server variables.

```typescript theme={null}
type ClientEnv<TEnv extends Record<string, unknown>> = {
  [K in keyof TEnv as TEnv[K] extends { readonly [SERVER_ONLY_BRAND]: void }
    ? never
    : K]: TEnv[K]
}
```

```typescript theme={null}
import type { ClientEnv } from 'next-safe-env'
import { env } from '@/env'

type ClientVars = ClientEnv<typeof env>

// TypeScript errors if you reference a server key here
function renderHeader(vars: ClientVars) {
  return vars.NEXT_PUBLIC_APP_NAME  // ✅ fine
  // vars.DATABASE_URL              // ✗ property does not exist on ClientVars
}
```

***

## `InferEnv<TServer, TClient>`

`InferEnv<TServer, TClient>` is the full return type of `createEnv()`. Server keys are wrapped in `ServerOnly<T>`; client keys are their plain inferred types. The whole object is `Readonly`.

```typescript theme={null}
type InferEnv<
  TServer extends Schema | ZodObjectLike<Record<string, unknown>>,
  TClient extends Schema | ZodObjectLike<Record<string, unknown>>,
> = Readonly<
  { [K in keyof InferInput<TServer>]: ServerOnly<InferInput<TServer>[K]> } &
    InferInput<TClient>
>
```

You rarely need to reference `InferEnv` directly - the return type of `createEnv()` is inferred automatically. Use it when you need to pass the env type as a generic argument elsewhere.

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

type MyEnv = InferEnv<typeof serverSchema, typeof clientSchema>
```

***

## `InferSchema<T>`

`InferSchema<T>` maps a `Schema` (a `Record<string, FieldValidator<unknown>>`) to the object type its validators produce. It reads the phantom `_type` property from each `FieldValidator` to extract the output type.

```typescript theme={null}
type InferSchema<T extends Schema> = {
  [K in keyof T]: T[K] extends FieldValidator<infer V> ? V : never
}
```

```typescript theme={null}
import type { InferSchema } from 'next-safe-env'
import { str, url, port } from 'next-safe-env'

const serverSchema = {
  DATABASE_URL: url(),
  PORT:         port().default(3000),
  NODE_ENV:     str().enum(['development', 'production', 'test']),
}

type ServerShape = InferSchema<typeof serverSchema>
// { DATABASE_URL: string; PORT: number; NODE_ENV: 'development' | 'production' | 'test' }
```

***

## `InferInput<T>`

`InferInput<T>` infers the output type from either a native `Schema` or a `ZodObjectLike`. For Zod schemas it reads the `_output` phantom property; for native schemas it delegates to `InferSchema<T>`.

```typescript theme={null}
type InferInput<T> = T extends ZodObjectLike<
  infer O extends Record<string, unknown>
>
  ? O
  : T extends Schema
    ? InferSchema<T>
    : never
```

This type is used internally by `InferEnv` to handle both native and Zod schemas uniformly.

***

## `EnvConfig<TServer, TClient>`

`EnvConfig<TServer, TClient>` is the shape of the config object passed to `createEnv()`. Refer to the [createEnv() reference](/api/create-env) for a full description of each field.

```typescript theme={null}
type EnvConfig<
  TServer extends Schema | ZodObjectLike<Record<string, unknown>>,
  TClient extends Schema | ZodObjectLike<Record<string, unknown>>,
> = {
  server: TServer
  client: TClient
  runtimeEnv: {
    [K in (
      | (TServer extends ZodObjectLike<infer O extends Record<string, unknown>>
          ? keyof O
          : keyof TServer)
      | (TClient extends ZodObjectLike<infer O extends Record<string, unknown>>
          ? keyof O
          : keyof TClient)
    ) &
      string]?: string | undefined
  }
  adapter?: 'nextjs' | 'node' | 'edge' | 'vite'
  skipValidation?: boolean
  onValidationError?: (error: ValidationErrorShape) => never
}
```

***

## `ValidationFailure`

`ValidationFailure` describes a single failed field produced during validation. An array of these is attached to `EnvValidationError` and passed to `onValidationError`.

```typescript theme={null}
type ValidationFailure = {
  field: string
  expected: string
  received: string
  message: string
}
```

<ResponseField name="field" type="string" required>
  The environment variable name that failed, e.g. `"DATABASE_URL"`.
</ResponseField>

<ResponseField name="expected" type="string" required>
  A human-readable description of what was expected, e.g. `"valid URL"` or `"length >= 32"`.
</ResponseField>

<ResponseField name="received" type="string" required>
  The actual value (or `"undefined"`) that was received.
</ResponseField>

<ResponseField name="message" type="string" required>
  The full error message combining `expected` and `received`, e.g. `"Expected valid URL. Got: \"postgres-localhost\""`.
</ResponseField>

***

## `ValidationStats`

`ValidationStats` provides a summary count of how many variables were checked and how many failed, split by `server` and `client`. It is attached to `EnvValidationError`.

```typescript theme={null}
type ValidationStats = {
  serverTotal: number
  clientTotal: number
  serverFailed: number
  clientFailed: number
}
```

<ResponseField name="serverTotal" type="number" required>
  Total number of keys in the `server` schema.
</ResponseField>

<ResponseField name="clientTotal" type="number" required>
  Total number of keys in the `client` schema.
</ResponseField>

<ResponseField name="serverFailed" type="number" required>
  Number of `server` keys that failed validation.
</ResponseField>

<ResponseField name="clientFailed" type="number" required>
  Number of `client` keys that failed validation.
</ResponseField>

***

## `FieldValidator<T>`

`FieldValidator<T>` is the interface every validator class implements. The generic `T` is the TypeScript output type - `string`, `number`, `boolean`, or their `| undefined` variants. The `_type` property is a phantom: it never exists at runtime and is only used by `InferSchema<T>` to extract `T`.

```typescript theme={null}
interface FieldValidator<T = unknown> {
  readonly isOptional: boolean
  readonly defaultValue: T | undefined
  // phantom - satisfies the interface but never assigned at runtime (use `declare`)
  _type: T
  parse(rawValue: unknown, fieldName: string): T
}
```

<ResponseField name="isOptional" type="boolean" required>
  `true` when `.optional()` has been called on the validator.
</ResponseField>

<ResponseField name="defaultValue" type="T | undefined" required>
  The fallback value set by `.default(v)`, or `undefined` if no default was configured.
</ResponseField>

<ResponseField name="parse" type="(rawValue: unknown, fieldName: string) => T" required>
  Parses and validates `rawValue`. Throws a `FieldError` if the value is invalid. Called once per field during the validation pass inside `createEnv()`.
</ResponseField>

***

## `Adapter`

`Adapter` is the interface that all built-in adapters (`nextjs`, `node`, `edge`, `vite`) implement. You can also implement this interface to build a custom adapter.

```typescript theme={null}
type Adapter = {
  name: string
  beforeValidate(
    serverSchema: Schema,
    clientSchema: Schema,
    rawEnv: Record<string, string | undefined>,
  ): Record<string, string | undefined>
  afterValidate<T extends Record<string, unknown>>(env: T): T
}
```

<ResponseField name="name" type="string" required>
  Identifier for the adapter, e.g. `"nextjs"` or `"node"`.
</ResponseField>

<ResponseField name="beforeValidate" type="function" required>
  Called before any field is validated. Receives the server schema, client schema, and raw env map. Can throw to block startup (e.g., when a `NEXT_PUBLIC_` prefix is missing). Returns the raw env map - possibly filtered - that validation runs against.
</ResponseField>

<ResponseField name="afterValidate" type="function" required>
  Called after all fields pass validation. Receives the fully-validated env object and returns it, optionally with keys stripped (e.g., the `edge` adapter removes all non-`NEXT_PUBLIC_` keys unconditionally).
</ResponseField>

***

## Zod interop types

These types are exported for advanced Zod interop use cases. They are duck-typed interfaces - no `zod` package import is required.

### `ZodTypeLike<T>`

A duck-typed interface matching `zod.ZodType`. `createEnv()` detects Zod schemas at runtime using this structural shape.

```typescript theme={null}
interface ZodTypeLike<T = unknown> {
  readonly _output: T
  safeParse(
    data: unknown,
  ): { success: true; data: T } | { success: false; error: ZodErrorLike }
}
```

### `ZodObjectLike<T>`

A duck-typed interface matching `zod.ZodObject`. Required for the `createEnv({ server: z.object({ ... }) })` syntax.

```typescript theme={null}
interface ZodObjectLike<
  T extends Record<string, unknown> = Record<string, unknown>,
> extends ZodTypeLike<T> {
  readonly shape: Record<string, ZodTypeLike<unknown>>
}
```

### `ZodErrorLike`

A duck-typed interface matching the error shape exposed by `zod.ZodError`.

```typescript theme={null}
type ZodErrorLike = {
  readonly errors: ReadonlyArray<{
    readonly path: ReadonlyArray<string | number>
    readonly message: string
  }>
}
```
