CtrlK
BlogDocsLog inGet started
Tessl Logo

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

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

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

@t3-oss/env-nextjs

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

Package Information

  • Package Name: @t3-oss/env-nextjs
  • Package Type: npm
  • Language: TypeScript
  • Installation: npm install @t3-oss/env-nextjs

Core Imports

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

For CommonJS:

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

Basic Usage

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

export const env = createEnv({
  // Server-side environment variables (not available on client)
  server: {
    DATABASE_URL: z.string().url(),
    OPEN_AI_API_KEY: z.string().min(1),
  },
  // Client-side environment variables (requires NEXT_PUBLIC_ prefix)
  client: {
    NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: z.string().min(1),
  },
  // Shared environment variables (available on both server and client)
  shared: {
    NODE_ENV: z.enum(["development", "test", "production"]),
  },
  // Runtime environment values
  runtimeEnv: {
    DATABASE_URL: process.env.DATABASE_URL,
    OPEN_AI_API_KEY: process.env.OPEN_AI_API_KEY,
    NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY,
    NODE_ENV: process.env.NODE_ENV,
  },
});

// Access environment variables with full type safety
console.log(env.DATABASE_URL); // string
console.log(env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY); // string
console.log(env.NODE_ENV); // "development" | "test" | "production"

Architecture

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

  • Core Function: createEnv function that creates typesafe environment variable schemas with Next.js-specific configurations
  • Client Prefix Enforcement: Automatic validation that client-side variables use the required NEXT_PUBLIC_ prefix
  • Runtime Environment Management: Support for both traditional runtimeEnv and experimental experimental__runtimeEnv modes
  • Type Safety: Full TypeScript integration with compile-time type checking and runtime validation
  • Standard Schema Compatibility: Works with any Standard Schema-compliant validator (Zod, Valibot, Arktype)
  • Preset System: Pre-configured environment variable schemas for popular hosting platforms and services

Capabilities

Environment Schema Creation

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

function createEnv<
  TServer extends StandardSchemaDictionary = NonNullable<unknown>,
  TClient extends Record<`NEXT_PUBLIC_${string}`, StandardSchemaV1> = NonNullable<unknown>,
  TShared extends StandardSchemaDictionary = NonNullable<unknown>,
  const TExtends extends Array<Record<string, unknown>> = [],
  TFinalSchema extends StandardSchemaV1<{}, {}> = DefaultCombinedSchema<TServer, TClient, TShared>
>(opts: Options<TServer, TClient, TShared, TExtends, TFinalSchema>): CreateEnv<TFinalSchema, TExtends>;

type Options<
  TServer extends StandardSchemaDictionary,
  TClient extends Record<`NEXT_PUBLIC_${string}`, StandardSchemaV1>,
  TShared extends StandardSchemaDictionary,
  TExtends extends Array<Record<string, unknown>>,
  TFinalSchema extends StandardSchemaV1<{}, {}>
> = Omit<
  StrictOptions<"NEXT_PUBLIC_", TServer, TClient, TShared, TExtends> &
    ServerClientOptions<"NEXT_PUBLIC_", TServer, TClient> &
    CreateSchemaOptions<TServer, TClient, TShared, TFinalSchema>,
  "runtimeEnvStrict" | "runtimeEnv" | "clientPrefix"
> & (
  | {
      runtimeEnv: StrictOptions<"NEXT_PUBLIC_", TServer, TClient, TShared, TExtends>["runtimeEnvStrict"];
      experimental__runtimeEnv?: never;
    }
  | {
      runtimeEnv?: never;
      experimental__runtimeEnv: Record<
        | {
            [TKey in keyof TClient]: TKey extends `NEXT_PUBLIC_${string}` ? TKey : never;
          }[keyof TClient]
        | {
            [TKey in keyof TShared]: TKey extends string ? TKey : never;
          }[keyof TShared],
        string | boolean | number | undefined
      >;
    }
);

Environment Schema Creation

Zod Presets

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.

// Example preset functions
function vercel(): Readonly<VercelEnv>;
function railway(): Readonly<RailwayEnv>;
function render(): Readonly<RenderEnv>;
function netlify(): Readonly<NetlifyEnv>;

Zod Presets

Arktype Presets

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

// Example preset functions  
function vercel(): Readonly<VercelEnv>;
function railway(): Readonly<RailwayEnv>;
function render(): Readonly<RenderEnv>;
function netlify(): Readonly<NetlifyEnv>;

Arktype Presets

Valibot Presets

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

// Example preset functions
function vercel(): Readonly<VercelEnv>;
function railway(): Readonly<RailwayEnv>;
function render(): Readonly<RenderEnv>;
function netlify(): Readonly<NetlifyEnv>;

Valibot Presets

Types

// Client prefix type
type ClientPrefix = "NEXT_PUBLIC_";

// Standard schema types (from @t3-oss/env-core)
interface StandardSchemaDictionary {
  [key: string]: StandardSchemaV1;
}

interface StandardSchemaV1<Input = any, Output = Input> {
  readonly "~standard": {
    readonly version: 1;
    readonly vendor: string;
    readonly validate: (value: unknown) => StandardSchemaV1.Result<Output> | Promise<StandardSchemaV1.Result<Output>>;
    readonly types?: StandardSchemaV1.Types<Input, Output> | undefined;
  };
}

declare namespace StandardSchemaV1 {
  // Standard Schema result types
  type Result<Output> = SuccessResult<Output> | FailureResult;
  
  interface SuccessResult<Output> {
    readonly value: Output;
    readonly issues?: undefined;
  }
  
  interface FailureResult {
    readonly issues: ReadonlyArray<Issue>;
  }
  
  // Issue interface for validation errors
  interface Issue {
    readonly message: string;
    readonly path?: ReadonlyArray<PropertyKey | PathSegment> | undefined;
  }
  
  interface PathSegment {
    readonly key: PropertyKey;
  }
  
  interface Types<Input = unknown, Output = Input> {
    readonly input: Input;
    readonly output: Output;
  }
}

// Base configuration options
interface BaseOptions<
  TShared extends StandardSchemaDictionary,
  TExtends extends Array<Record<string, unknown>>
> {
  /** How to determine whether the app is running on the server or the client */
  isServer?: boolean;
  /** Shared variables available on both client and server */
  shared?: TShared;
  /** Extend presets */
  extends?: TExtends;
  /** Called when validation fails */
  onValidationError?: (issues: readonly StandardSchemaV1.Issue[]) => never;
  /** Called when a server-side environment variable is accessed on the client */
  onInvalidAccess?: (variable: string) => never;
  /** Whether to skip validation of environment variables */
  skipValidation?: boolean;
  /** Treat empty strings as undefined for better default value handling */
  emptyStringAsUndefined?: boolean;
}

// Loose runtime environment options
interface LooseOptions<
  TShared extends StandardSchemaDictionary,
  TExtends extends Array<Record<string, unknown>>
> extends BaseOptions<TShared, TExtends> {
  runtimeEnvStrict?: never;
  /** Runtime environment object - usually process.env */
  runtimeEnv: Record<string, string | boolean | number | undefined>;
}

// Strict runtime environment options  
interface StrictOptions<
  TPrefix extends string | undefined,
  TServer extends StandardSchemaDictionary,
  TClient extends StandardSchemaDictionary,
  TShared extends StandardSchemaDictionary,
  TExtends extends Array<Record<string, unknown>>
> extends BaseOptions<TShared, TExtends> {
  /** Strict runtime environment that enforces all variables are specified */
  runtimeEnvStrict: Record<string, string | boolean | number | undefined>;
  runtimeEnv?: never;
}

// Client-side configuration options
interface ClientOptions<
  TPrefix extends string | undefined,
  TClient extends StandardSchemaDictionary
> {
  /** Prefix for client-side variables (e.g., NEXT_PUBLIC_) */
  clientPrefix: TPrefix;
  /** Client-side environment variable schemas */
  client: Partial<Record<keyof TClient, TClient[keyof TClient]>>;
}

// Server-side configuration options
interface ServerOptions<
  TPrefix extends string | undefined,
  TServer extends StandardSchemaDictionary
> {
  /** Server-side environment variable schemas */
  server: Partial<Record<keyof TServer, TServer[keyof TServer]>>;
}

// Schema creation options
interface CreateSchemaOptions<
  TServer extends StandardSchemaDictionary,
  TClient extends StandardSchemaDictionary,
  TShared extends StandardSchemaDictionary,
  TFinalSchema extends StandardSchemaV1<{}, {}>
> {
  /** Custom function to combine the schemas */
  createFinalSchema?: (
    shape: TServer & TClient & TShared,
    isServer: boolean
  ) => TFinalSchema;
}

// Combined server/client options
type ServerClientOptions<
  TPrefix extends string | undefined,
  TServer extends StandardSchemaDictionary,  
  TClient extends StandardSchemaDictionary
> =
  | (ClientOptions<TPrefix, TClient> & ServerOptions<TPrefix, TServer>)
  | (ServerOptions<TPrefix, TServer> & Impossible<ClientOptions<never, never>>)
  | (ClientOptions<TPrefix, TClient> & Impossible<ServerOptions<never, never>>);

// Environment creation options
type EnvOptions<
  TPrefix extends string | undefined,
  TServer extends StandardSchemaDictionary,
  TClient extends StandardSchemaDictionary,
  TShared extends StandardSchemaDictionary,
  TExtends extends Array<Record<string, unknown>>,
  TFinalSchema extends StandardSchemaV1<{}, {}>
> = (
  | (LooseOptions<TShared, TExtends> & ServerClientOptions<TPrefix, TServer, TClient>)
  | (StrictOptions<TPrefix, TServer, TClient, TShared, TExtends> & ServerClientOptions<TPrefix, TServer, TClient>)
) & CreateSchemaOptions<TServer, TClient, TShared, TFinalSchema>;

// Core creation types
type CreateEnv<
  TFinalSchema extends StandardSchemaV1<{}, {}>,
  TExtends extends Array<Record<string, unknown>>
> = Readonly<Simplify<Reduce<[StandardSchemaV1.InferOutput<TFinalSchema>, ...TExtends]>>>;

type DefaultCombinedSchema<
  TServer extends StandardSchemaDictionary,
  TClient extends StandardSchemaDictionary,
  TShared extends StandardSchemaDictionary
> = StandardSchemaV1<
  {},
  UndefinedOptional<StandardSchemaDictionary.InferOutput<TServer & TClient & TShared>>
>;

// Utility types
type ErrorMessage<T extends string> = T;
type Simplify<T> = { [P in keyof T]: T[P] } & {};
type UndefinedOptional<T> = Partial<Pick<T, PossiblyUndefinedKeys<T>>> & Omit<T, PossiblyUndefinedKeys<T>>;
type PossiblyUndefinedKeys<T> = {
  [K in keyof T]: undefined extends T[K] ? K : never;
}[keyof T];
type Impossible<T extends Record<string, any>> = Partial<Record<keyof T, never>>;
type Reduce<
  TArr extends Record<string, unknown>[],
  TAcc = object
> = TArr extends []
  ? TAcc
  : TArr extends [infer Head, ...infer Tail]
    ? Tail extends Record<string, unknown>[]
      ? Mutable<Head> & Omit<Reduce<Tail, TAcc>, keyof Head>
      : never
    : never;
type Mutable<T> = T extends Readonly<infer U> ? U : T;
Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/@t3-oss/env-nextjs@0.13.x
Publish Source
CLI
Badge
tessl/npm-t3-oss--env-nextjs badge