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
Overview
Eval results
Files

core.mddocs/

Environment Schema Creation

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

Capabilities

createEnv Function

Creates a new environment variable schema with Next.js-specific configurations, enforcing the NEXT_PUBLIC_ prefix for client-side variables and providing runtime validation.

/**
 * Create a new environment variable schema with Next.js-specific configurations
 * @param opts - Configuration options for the environment schema
 * @returns Validated environment variables with full type safety
 */
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>;

Generic Parameters:

  • TServer - Schema dictionary for server-side environment variables
  • TClient - Schema dictionary for client-side environment variables (must use NEXT_PUBLIC_ prefix)
  • TShared - Schema dictionary for shared environment variables (available on both server and client)
  • TExtends - Array of preset environment objects to extend from
  • TFinalSchema - Final combined schema type

Configuration Options

Configuration options for the createEnv function with Next.js-specific runtime environment handling.

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"
> & (
  | {
      /** Manual destruction of process.env. Required for Next.js < 13.4.4 */
      runtimeEnv: StrictOptions<"NEXT_PUBLIC_", TServer, TClient, TShared, TExtends>["runtimeEnvStrict"];
      experimental__runtimeEnv?: never;
    }
  | {
      runtimeEnv?: never;
      /** 
       * Can be used for Next.js ^13.4.4 since they stopped static analysis of server side process.env.
       * Only client side process.env is statically analyzed and needs to be manually destructured.
       */
      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
      >;
    }
);

Configuration Properties:

Schema Definition:

  • server?: TServer - Server-side environment variable schemas (not available on client)
  • client?: TClient - Client-side environment variable schemas (must be prefixed with NEXT_PUBLIC_)
  • shared?: TShared - Shared environment variable schemas (available on both server and client)
  • extends?: TExtends - Array of preset environment objects to extend from

Runtime Environment:

  • runtimeEnv?: Record<string, any> - Manual process.env destruction for Next.js < 13.4.4
  • experimental__runtimeEnv?: Record<string, any> - Experimental runtime environment for Next.js >= 13.4.4

Base Configuration Options:

  • isServer?: boolean - How to determine whether the app is running on the server or the client (default: typeof window === "undefined")
  • onValidationError?: (issues: readonly StandardSchemaV1.Issue[]) => never - Called when validation fails (default: logs error and throws)
  • onInvalidAccess?: (variable: string) => never - Called when server-side environment variable is accessed on client (default: throws error)
  • skipValidation?: boolean - Whether to skip validation of environment variables (default: false)
  • emptyStringAsUndefined?: boolean - Treat empty strings as undefined for better default value handling (default: false)
  • createFinalSchema?: (shape: TServer & TClient & TShared, isServer: boolean) => TFinalSchema - Custom function to combine the schemas

Usage Examples

Basic Environment Schema

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

const env = createEnv({
  server: {
    DATABASE_URL: z.string().url(),
    JWT_SECRET: z.string().min(32),
  },
  client: {
    NEXT_PUBLIC_APP_URL: z.string().url(),
    NEXT_PUBLIC_ANALYTICS_ID: z.string().min(1),
  },
  runtimeEnv: {
    DATABASE_URL: process.env.DATABASE_URL,
    JWT_SECRET: process.env.JWT_SECRET,
    NEXT_PUBLIC_APP_URL: process.env.NEXT_PUBLIC_APP_URL,
    NEXT_PUBLIC_ANALYTICS_ID: process.env.NEXT_PUBLIC_ANALYTICS_ID,
  },
});

With Shared Variables

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

const env = createEnv({
  server: {
    DATABASE_URL: z.string().url(),
  },
  client: {
    NEXT_PUBLIC_APP_URL: z.string().url(),
  },
  shared: {
    NODE_ENV: z.enum(["development", "test", "production"]),
    APP_VERSION: z.string().default("1.0.0"),
  },
  runtimeEnv: {
    DATABASE_URL: process.env.DATABASE_URL,
    NEXT_PUBLIC_APP_URL: process.env.NEXT_PUBLIC_APP_URL,
    NODE_ENV: process.env.NODE_ENV,
    APP_VERSION: process.env.APP_VERSION,
  },
});

Experimental Runtime Environment (Next.js >= 13.4.4)

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

const env = createEnv({
  server: {
    DATABASE_URL: z.string().url(),
    JWT_SECRET: z.string().min(32),
  },
  client: {
    NEXT_PUBLIC_APP_URL: z.string().url(),
  },
  shared: {
    NODE_ENV: z.enum(["development", "test", "production"]),
  },
  // Only specify client and shared variables
  experimental__runtimeEnv: {
    NEXT_PUBLIC_APP_URL: process.env.NEXT_PUBLIC_APP_URL,
    NODE_ENV: process.env.NODE_ENV,
  },
});

Extending Presets

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

const preset = vercel();

const env = createEnv({
  server: {
    DATABASE_URL: z.string().url(),
  },
  client: {
    NEXT_PUBLIC_APP_URL: z.string().url(),
  },
  extends: [preset],
  runtimeEnv: {
    DATABASE_URL: process.env.DATABASE_URL,
    NEXT_PUBLIC_APP_URL: process.env.NEXT_PUBLIC_APP_URL,
    // Preset variables are automatically available
  },
});

With Transformations

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

const env = createEnv({
  server: {
    PORT: z.string().transform(Number),
    ENABLE_LOGGING: z.string().transform((val) => val === "true"),
  },
  client: {
    NEXT_PUBLIC_API_URL: z.string().url(),
  },
  runtimeEnv: {
    PORT: process.env.PORT,
    ENABLE_LOGGING: process.env.ENABLE_LOGGING,
    NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL,
  },
});

// env.PORT is now a number
// env.ENABLE_LOGGING is now a boolean

Error Handling

The package throws validation errors in the following scenarios:

  • Invalid Environment Variables: When environment variables don't match their schema validation rules
  • Missing Required Variables: When required environment variables are not provided in runtimeEnv
  • Client Access Violation: When server-side variables are accessed on the client-side (throws runtime error)
  • Prefix Violation: When client-side variables don't use the required NEXT_PUBLIC_ prefix (compile-time error)
  • Schema Mismatch: When runtimeEnv keys don't match the defined schema keys
// This will cause a compile-time error
createEnv({
  server: {
    // @ts-expect-error - server variables cannot have NEXT_PUBLIC_ prefix
    NEXT_PUBLIC_SECRET: z.string(),
  },
  client: {
    // @ts-expect-error - client variables must have NEXT_PUBLIC_ prefix  
    API_KEY: z.string(),
  },
  runtimeEnv: {},
});

Install with Tessl CLI

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

docs

core.md

index.md

presets-arktype.md

presets-valibot.md

presets-zod.md

tile.json