or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

tessl/npm-t3-oss--env-nextjs

Typesafe environment variable validation and management for Next.js applications with runtime compatibility enforcement.

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/@t3-oss/env-nextjs@0.13.x

To install, run

npx @tessl/cli install tessl/npm-t3-oss--env-nextjs@0.13.0

0

# @t3-oss/env-nextjs

1

2

@t3-oss/env-nextjs provides typesafe environment variable validation and management specifically designed for Next.js applications. This package automatically enforces Next.js naming conventions (NEXT_PUBLIC_ prefix for client variables), ensures compatibility across all Next.js runtime environments (Node.js server, Edge Runtime, and browser client), and provides compile-time type checking with runtime validation using Standard Schema-compliant validators.

3

4

## Package Information

5

6

- **Package Name**: @t3-oss/env-nextjs

7

- **Package Type**: npm

8

- **Language**: TypeScript

9

- **Installation**: `npm install @t3-oss/env-nextjs`

10

11

## Core Imports

12

13

```typescript

14

import { createEnv } from "@t3-oss/env-nextjs";

15

```

16

17

For CommonJS:

18

19

```javascript

20

const { createEnv } = require("@t3-oss/env-nextjs");

21

```

22

23

## Basic Usage

24

25

```typescript

26

import { createEnv } from "@t3-oss/env-nextjs";

27

import { z } from "zod";

28

29

export const env = createEnv({

30

// Server-side environment variables (not available on client)

31

server: {

32

DATABASE_URL: z.string().url(),

33

OPEN_AI_API_KEY: z.string().min(1),

34

},

35

// Client-side environment variables (requires NEXT_PUBLIC_ prefix)

36

client: {

37

NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: z.string().min(1),

38

},

39

// Shared environment variables (available on both server and client)

40

shared: {

41

NODE_ENV: z.enum(["development", "test", "production"]),

42

},

43

// Runtime environment values

44

runtimeEnv: {

45

DATABASE_URL: process.env.DATABASE_URL,

46

OPEN_AI_API_KEY: process.env.OPEN_AI_API_KEY,

47

NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY,

48

NODE_ENV: process.env.NODE_ENV,

49

},

50

});

51

52

// Access environment variables with full type safety

53

console.log(env.DATABASE_URL); // string

54

console.log(env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY); // string

55

console.log(env.NODE_ENV); // "development" | "test" | "production"

56

```

57

58

## Architecture

59

60

@t3-oss/env-nextjs is built around several key components:

61

62

- **Core Function**: `createEnv` function that creates typesafe environment variable schemas with Next.js-specific configurations

63

- **Client Prefix Enforcement**: Automatic validation that client-side variables use the required `NEXT_PUBLIC_` prefix

64

- **Runtime Environment Management**: Support for both traditional `runtimeEnv` and experimental `experimental__runtimeEnv` modes

65

- **Type Safety**: Full TypeScript integration with compile-time type checking and runtime validation

66

- **Standard Schema Compatibility**: Works with any Standard Schema-compliant validator (Zod, Valibot, Arktype)

67

- **Preset System**: Pre-configured environment variable schemas for popular hosting platforms and services

68

69

## Capabilities

70

71

### Environment Schema Creation

72

73

Core functionality for creating typesafe environment variable schemas with Next.js-specific validation rules and runtime compatibility enforcement.

74

75

```typescript { .api }

76

function createEnv<

77

TServer extends StandardSchemaDictionary = NonNullable<unknown>,

78

TClient extends Record<`NEXT_PUBLIC_${string}`, StandardSchemaV1> = NonNullable<unknown>,

79

TShared extends StandardSchemaDictionary = NonNullable<unknown>,

80

const TExtends extends Array<Record<string, unknown>> = [],

81

TFinalSchema extends StandardSchemaV1<{}, {}> = DefaultCombinedSchema<TServer, TClient, TShared>

82

>(opts: Options<TServer, TClient, TShared, TExtends, TFinalSchema>): CreateEnv<TFinalSchema, TExtends>;

83

84

type Options<

85

TServer extends StandardSchemaDictionary,

86

TClient extends Record<`NEXT_PUBLIC_${string}`, StandardSchemaV1>,

87

TShared extends StandardSchemaDictionary,

88

TExtends extends Array<Record<string, unknown>>,

89

TFinalSchema extends StandardSchemaV1<{}, {}>

90

> = Omit<

91

StrictOptions<"NEXT_PUBLIC_", TServer, TClient, TShared, TExtends> &

92

ServerClientOptions<"NEXT_PUBLIC_", TServer, TClient> &

93

CreateSchemaOptions<TServer, TClient, TShared, TFinalSchema>,

94

"runtimeEnvStrict" | "runtimeEnv" | "clientPrefix"

95

> & (

96

| {

97

runtimeEnv: StrictOptions<"NEXT_PUBLIC_", TServer, TClient, TShared, TExtends>["runtimeEnvStrict"];

98

experimental__runtimeEnv?: never;

99

}

100

| {

101

runtimeEnv?: never;

102

experimental__runtimeEnv: Record<

103

| {

104

[TKey in keyof TClient]: TKey extends `NEXT_PUBLIC_${string}` ? TKey : never;

105

}[keyof TClient]

106

| {

107

[TKey in keyof TShared]: TKey extends string ? TKey : never;

108

}[keyof TShared],

109

string | boolean | number | undefined

110

>;

111

}

112

);

113

```

114

115

[Environment Schema Creation](./core.md)

116

117

### Zod Presets

118

119

Pre-configured environment variable schemas for popular hosting platforms and services using Zod validators. Includes presets for Vercel, Railway, Render, Netlify, and many other platforms.

120

121

```typescript { .api }

122

// Example preset functions

123

function vercel(): Readonly<VercelEnv>;

124

function railway(): Readonly<RailwayEnv>;

125

function render(): Readonly<RenderEnv>;

126

function netlify(): Readonly<NetlifyEnv>;

127

```

128

129

[Zod Presets](./presets-zod.md)

130

131

### Arktype Presets

132

133

Pre-configured environment variable schemas using Arktype validators. Provides the same platform presets as Zod but using Arktype's type system for validation.

134

135

```typescript { .api }

136

// Example preset functions

137

function vercel(): Readonly<VercelEnv>;

138

function railway(): Readonly<RailwayEnv>;

139

function render(): Readonly<RenderEnv>;

140

function netlify(): Readonly<NetlifyEnv>;

141

```

142

143

[Arktype Presets](./presets-arktype.md)

144

145

### Valibot Presets

146

147

Pre-configured environment variable schemas using Valibot validators. Provides the same platform presets as Zod and Arktype but using Valibot's validation system.

148

149

```typescript { .api }

150

// Example preset functions

151

function vercel(): Readonly<VercelEnv>;

152

function railway(): Readonly<RailwayEnv>;

153

function render(): Readonly<RenderEnv>;

154

function netlify(): Readonly<NetlifyEnv>;

155

```

156

157

[Valibot Presets](./presets-valibot.md)

158

159

## Types

160

161

```typescript { .api }

162

// Client prefix type

163

type ClientPrefix = "NEXT_PUBLIC_";

164

165

// Standard schema types (from @t3-oss/env-core)

166

interface StandardSchemaDictionary {

167

[key: string]: StandardSchemaV1;

168

}

169

170

interface StandardSchemaV1<Input = any, Output = Input> {

171

readonly "~standard": {

172

readonly version: 1;

173

readonly vendor: string;

174

readonly validate: (value: unknown) => StandardSchemaV1.Result<Output> | Promise<StandardSchemaV1.Result<Output>>;

175

readonly types?: StandardSchemaV1.Types<Input, Output> | undefined;

176

};

177

}

178

179

declare namespace StandardSchemaV1 {

180

// Standard Schema result types

181

type Result<Output> = SuccessResult<Output> | FailureResult;

182

183

interface SuccessResult<Output> {

184

readonly value: Output;

185

readonly issues?: undefined;

186

}

187

188

interface FailureResult {

189

readonly issues: ReadonlyArray<Issue>;

190

}

191

192

// Issue interface for validation errors

193

interface Issue {

194

readonly message: string;

195

readonly path?: ReadonlyArray<PropertyKey | PathSegment> | undefined;

196

}

197

198

interface PathSegment {

199

readonly key: PropertyKey;

200

}

201

202

interface Types<Input = unknown, Output = Input> {

203

readonly input: Input;

204

readonly output: Output;

205

}

206

}

207

208

// Base configuration options

209

interface BaseOptions<

210

TShared extends StandardSchemaDictionary,

211

TExtends extends Array<Record<string, unknown>>

212

> {

213

/** How to determine whether the app is running on the server or the client */

214

isServer?: boolean;

215

/** Shared variables available on both client and server */

216

shared?: TShared;

217

/** Extend presets */

218

extends?: TExtends;

219

/** Called when validation fails */

220

onValidationError?: (issues: readonly StandardSchemaV1.Issue[]) => never;

221

/** Called when a server-side environment variable is accessed on the client */

222

onInvalidAccess?: (variable: string) => never;

223

/** Whether to skip validation of environment variables */

224

skipValidation?: boolean;

225

/** Treat empty strings as undefined for better default value handling */

226

emptyStringAsUndefined?: boolean;

227

}

228

229

// Loose runtime environment options

230

interface LooseOptions<

231

TShared extends StandardSchemaDictionary,

232

TExtends extends Array<Record<string, unknown>>

233

> extends BaseOptions<TShared, TExtends> {

234

runtimeEnvStrict?: never;

235

/** Runtime environment object - usually process.env */

236

runtimeEnv: Record<string, string | boolean | number | undefined>;

237

}

238

239

// Strict runtime environment options

240

interface StrictOptions<

241

TPrefix extends string | undefined,

242

TServer extends StandardSchemaDictionary,

243

TClient extends StandardSchemaDictionary,

244

TShared extends StandardSchemaDictionary,

245

TExtends extends Array<Record<string, unknown>>

246

> extends BaseOptions<TShared, TExtends> {

247

/** Strict runtime environment that enforces all variables are specified */

248

runtimeEnvStrict: Record<string, string | boolean | number | undefined>;

249

runtimeEnv?: never;

250

}

251

252

// Client-side configuration options

253

interface ClientOptions<

254

TPrefix extends string | undefined,

255

TClient extends StandardSchemaDictionary

256

> {

257

/** Prefix for client-side variables (e.g., NEXT_PUBLIC_) */

258

clientPrefix: TPrefix;

259

/** Client-side environment variable schemas */

260

client: Partial<Record<keyof TClient, TClient[keyof TClient]>>;

261

}

262

263

// Server-side configuration options

264

interface ServerOptions<

265

TPrefix extends string | undefined,

266

TServer extends StandardSchemaDictionary

267

> {

268

/** Server-side environment variable schemas */

269

server: Partial<Record<keyof TServer, TServer[keyof TServer]>>;

270

}

271

272

// Schema creation options

273

interface CreateSchemaOptions<

274

TServer extends StandardSchemaDictionary,

275

TClient extends StandardSchemaDictionary,

276

TShared extends StandardSchemaDictionary,

277

TFinalSchema extends StandardSchemaV1<{}, {}>

278

> {

279

/** Custom function to combine the schemas */

280

createFinalSchema?: (

281

shape: TServer & TClient & TShared,

282

isServer: boolean

283

) => TFinalSchema;

284

}

285

286

// Combined server/client options

287

type ServerClientOptions<

288

TPrefix extends string | undefined,

289

TServer extends StandardSchemaDictionary,

290

TClient extends StandardSchemaDictionary

291

> =

292

| (ClientOptions<TPrefix, TClient> & ServerOptions<TPrefix, TServer>)

293

| (ServerOptions<TPrefix, TServer> & Impossible<ClientOptions<never, never>>)

294

| (ClientOptions<TPrefix, TClient> & Impossible<ServerOptions<never, never>>);

295

296

// Environment creation options

297

type EnvOptions<

298

TPrefix extends string | undefined,

299

TServer extends StandardSchemaDictionary,

300

TClient extends StandardSchemaDictionary,

301

TShared extends StandardSchemaDictionary,

302

TExtends extends Array<Record<string, unknown>>,

303

TFinalSchema extends StandardSchemaV1<{}, {}>

304

> = (

305

| (LooseOptions<TShared, TExtends> & ServerClientOptions<TPrefix, TServer, TClient>)

306

| (StrictOptions<TPrefix, TServer, TClient, TShared, TExtends> & ServerClientOptions<TPrefix, TServer, TClient>)

307

) & CreateSchemaOptions<TServer, TClient, TShared, TFinalSchema>;

308

309

// Core creation types

310

type CreateEnv<

311

TFinalSchema extends StandardSchemaV1<{}, {}>,

312

TExtends extends Array<Record<string, unknown>>

313

> = Readonly<Simplify<Reduce<[StandardSchemaV1.InferOutput<TFinalSchema>, ...TExtends]>>>;

314

315

type DefaultCombinedSchema<

316

TServer extends StandardSchemaDictionary,

317

TClient extends StandardSchemaDictionary,

318

TShared extends StandardSchemaDictionary

319

> = StandardSchemaV1<

320

{},

321

UndefinedOptional<StandardSchemaDictionary.InferOutput<TServer & TClient & TShared>>

322

>;

323

324

// Utility types

325

type ErrorMessage<T extends string> = T;

326

type Simplify<T> = { [P in keyof T]: T[P] } & {};

327

type UndefinedOptional<T> = Partial<Pick<T, PossiblyUndefinedKeys<T>>> & Omit<T, PossiblyUndefinedKeys<T>>;

328

type PossiblyUndefinedKeys<T> = {

329

[K in keyof T]: undefined extends T[K] ? K : never;

330

}[keyof T];

331

type Impossible<T extends Record<string, any>> = Partial<Record<keyof T, never>>;

332

type Reduce<

333

TArr extends Record<string, unknown>[],

334

TAcc = object

335

> = TArr extends []

336

? TAcc

337

: TArr extends [infer Head, ...infer Tail]

338

? Tail extends Record<string, unknown>[]

339

? Mutable<Head> & Omit<Reduce<Tail, TAcc>, keyof Head>

340

: never

341

: never;

342

type Mutable<T> = T extends Readonly<infer U> ? U : T;

343

```