### Install Bun Source: https://github.com/t3-oss/t3-env/blob/main/README.md Commands to install the Bun runtime for development. ```sh # Linux & macOS curl -fsSL https://bun.sh/install | bash # Windows powershell -c "irm bun.sh/install.ps1 | iex" ``` -------------------------------- ### Install dependencies Source: https://github.com/t3-oss/t3-env/blob/main/README.md Install project dependencies using Bun. ```sh cd t3-env bun i ``` -------------------------------- ### Install Valibot Source: https://github.com/t3-oss/t3-env/blob/main/docs/src/app/docs/standard-schema/page.mdx Install the Valibot package via npm. ```bash npm install valibot ``` -------------------------------- ### Install @t3-oss/env-core with deno Source: https://github.com/t3-oss/t3-env/blob/main/packages/core/README.md Use this command to install the core package using deno. ```bash deno add jsr:@t3-oss/env-core ``` -------------------------------- ### Install @t3-oss/env-core with bun Source: https://github.com/t3-oss/t3-env/blob/main/packages/core/README.md Use this command to install the core package using bun. ```bash bun add @t3-oss/env-core ``` -------------------------------- ### Install Dependencies Source: https://github.com/t3-oss/t3-env/blob/main/docs/src/app/docs/nextjs/page.mdx Commands to install the required packages using pnpm or JSR. ```bash pnpm add @t3-oss/env-nextjs zod # or using JSR deno add jsr:@t3-oss/env-nextjs ``` -------------------------------- ### Install Zod Source: https://github.com/t3-oss/t3-env/blob/main/docs/src/app/docs/standard-schema/page.mdx Install the Zod package via npm. ```bash npm install zod ``` -------------------------------- ### Install @t3-oss/env-core with npm Source: https://github.com/t3-oss/t3-env/blob/main/packages/core/README.md Use this command to install the core package using npm. ```bash npm i @t3-oss/env-core ``` -------------------------------- ### Install @t3-oss/env-core with pnpm Source: https://github.com/t3-oss/t3-env/blob/main/packages/core/README.md Use this command to install the core package using pnpm. ```bash pnpm add @t3-oss/env-core ``` -------------------------------- ### Install ArkType Source: https://github.com/t3-oss/t3-env/blob/main/docs/src/app/docs/standard-schema/page.mdx Install the ArkType package via npm. ```bash npm install arktype ``` -------------------------------- ### Install dependencies Source: https://github.com/t3-oss/t3-env/blob/main/docs/src/app/docs/core/page.mdx Install the core package and a validator like Zod using npm or JSR. ```bash npm install @t3-oss/env-core zod # or using JSR deno add jsr:@t3-oss/env-core ``` -------------------------------- ### Install T3 Env for Nuxt Source: https://github.com/t3-oss/t3-env/blob/main/packages/nuxt/README.md Commands to install the package using various package managers. ```bash # npm npm i @t3-oss/env-nuxt # pnpm pnpm add @t3-oss/env-nuxt # bun bun add @t3-oss/env-nuxt # deno deno add jsr:@t3-oss/env-nuxt ``` -------------------------------- ### Install T3 Env Nuxt dependencies Source: https://github.com/t3-oss/t3-env/blob/main/docs/src/app/docs/nuxt/page.mdx Install the required packages using pnpm or Deno. ```bash pnpm add @t3-oss/env-nuxt zod # or using JSR deno add jsr:@t3-oss/env-nuxt ``` -------------------------------- ### Install T3 Env for Next.js Source: https://github.com/t3-oss/t3-env/blob/main/packages/nextjs/README.md Commands to install the @t3-oss/env-nextjs package using various package managers. ```bash # npm npm i @t3-oss/env-nextjs # pnpm pnpm add @t3-oss/env-nextjs # bun bun add @t3-oss/env-nextjs # deno deno add jsr:@t3-oss/env-nextjs ``` -------------------------------- ### Install T3 Env Nuxt package Source: https://github.com/t3-oss/t3-env/blob/main/README.md Commands to install the package using various package managers. ```bash # npm npm i @t3-oss/env-nuxt # pnpm pnpm add @t3-oss/env-nuxt # bun bun add @t3-oss/env-nuxt # deno deno add jsr:@t3-oss/env-nuxt ``` -------------------------------- ### Using ArkType Presets Source: https://context7.com/t3-oss/t3-env/llms.txt Integrate pre-defined ArkType schema configurations using presets, such as the Vercel preset, for streamlined environment variable setup. ```typescript // Using ArkType presets: import { vercel } from "@t3-oss/env-core/presets-arktype"; export const envWithPresets = createEnv({ server: { DATABASE_URL: type("string.url"), }, extends: [vercel()], runtimeEnv: process.env, }); ``` -------------------------------- ### Environment Variables with Valibot Source: https://context7.com/t3-oss/t3-env/llms.txt Configure environment variables using Valibot for schema validation. This example shows basic string, URL, number, boolean, and array parsing, including default values and transformations. ```typescript // src/env.ts import { createEnv } from "@t3-oss/env-core"; import * as v from "valibot"; export const env = createEnv({ server: { DATABASE_URL: v.pipe(v.string(), v.url()), PORT: v.optional(v.pipe(v.string(), v.transform(Number)), "3000"), API_KEY: v.pipe(v.string(), v.minLength(32)), // Boolean with fallback ENABLE_LOGGING: v.optional( v.pipe( v.string(), v.transform((s) => s === "true") ), "false" ), // Array from comma-separated string ALLOWED_IPS: v.pipe( v.string(), v.transform((s) => s.split(",")), v.array(v.string()) ), }, clientPrefix: "PUBLIC_", client: { PUBLIC_API_URL: v.pipe(v.string(), v.url()), }, runtimeEnv: process.env, }); ``` -------------------------------- ### Define Environment Variables with Zod Source: https://github.com/t3-oss/t3-env/blob/main/packages/core/README.md This example demonstrates how to create typesafe environment variables using t3-env and Zod. It shows how to define server-only variables, client variables prefixed with PUBLIC_, and specifies the runtime environment for validation. ```typescript // src/env.ts import { createEnv } from "@t3-oss/env-core"; import * as z from "zod"; export const env = createEnv({ /* * Serverside Environment variables, not available on the client. * Will throw if you access these variables on the client. */ server: { DATABASE_URL: z.url(), OPEN_AI_API_KEY: z.string().min(1), }, /* * Environment variables available on the client (and server). * * 💡 You'll get type errors if these are not prefixed with PUBLIC_. */ clientPrefix: 'PUBLIC_', client: { PUBLIC_CLERK_PUBLISHABLE_KEY: z.string().min(1), }, /* * Specify what values should be validated by your schemas above. */ runtimeEnv: process.env, }); ``` -------------------------------- ### Environment Variables with ArkType Source: https://context7.com/t3-oss/t3-env/llms.txt Configure environment variables using ArkType for schema validation with TypeScript-like syntax. This example includes URL, numeric parsing, string length, and enum-like validation. ```typescript // src/env.ts import { createEnv } from "@t3-oss/env-core"; import { type } from "arktype"; export const env = createEnv({ server: { DATABASE_URL: type("string.url"), PORT: type("string.numeric.parse"), API_KEY: type("string >= 32"), // Enum-like validation NODE_ENV: type("'development' | 'production' | 'test'"), // Optional with string pattern LOG_LEVEL: type("'debug' | 'info' | 'warn' | 'error' | undefined"), }, clientPrefix: "PUBLIC_", client: { PUBLIC_APP_URL: type("string.url"), }, runtimeEnv: process.env, }); ``` -------------------------------- ### Custom Schema Refinement with createFinalSchema (Zod) Source: https://context7.com/t3-oss/t3-env/llms.txt Use `createFinalSchema` to add cross-field validation, conditional requirements, or custom transformations based on server/client context. This example demonstrates conditional validation for authentication fields using Zod. ```typescript // src/env.ts import { createEnv } from "@t3-oss/env-core"; import * as z from "zod"; export const env = createEnv({ server: { SKIP_AUTH: z.coerce.boolean().optional(), EMAIL: z.string().email().optional(), PASSWORD: z.string().min(8).optional(), AUTH_PROVIDER: z.enum(["local", "oauth", "none"]).optional(), OAUTH_CLIENT_ID: z.string().optional(), OAUTH_CLIENT_SECRET: z.string().optional(), }, runtimeEnv: process.env, emptyStringAsUndefined: true, // Custom schema with cross-field validation createFinalSchema: (shape, isServer) => z.object(shape).transform((env, ctx) => { // Skip auth validation on client if (!isServer || env.SKIP_AUTH) { return { ...env, SKIP_AUTH: true as const }; } // Validate based on auth provider if (env.AUTH_PROVIDER === "local") { if (!env.EMAIL || !env.PASSWORD) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: "EMAIL and PASSWORD are required when AUTH_PROVIDER is 'local'", }); return z.NEVER; } } if (env.AUTH_PROVIDER === "oauth") { if (!env.OAUTH_CLIENT_ID || !env.OAUTH_CLIENT_SECRET) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: "OAUTH_CLIENT_ID and OAUTH_CLIENT_SECRET are required for OAuth", }); return z.NEVER; } } return env; }), }); // .env for local auth: // AUTH_PROVIDER=local // EMAIL=admin@example.com // PASSWORD=securepassword123 // .env for OAuth: // AUTH_PROVIDER=oauth // OAUTH_CLIENT_ID=your-client-id // OAUTH_CLIENT_SECRET=your-client-secret // .env to skip auth: // SKIP_AUTH=true ``` -------------------------------- ### Coerce Booleans from Strings with t3-env and Zod Source: https://github.com/t3-oss/t3-env/blob/main/docs/src/app/docs/recipes/page.mdx Use `z.string().transform()` for custom boolean coercion logic, or `z.string().refine()` to strictly validate and then transform. Ensure your schema starts with `z.string()` before applying transforms. ```typescript export const env = createEnv({ server: { COERCED_BOOLEAN: z .string() // transform to boolean using preferred coercion logic .transform((s) => s !== "false" && s !== "0"), ONLY_BOOLEAN: z .string() // only allow "true" or "false" .refine((s) => s === "true" || s === "false") // transform to boolean .transform((s) => s === "true"), }, // ... }); ``` -------------------------------- ### Using Valibot Presets Source: https://context7.com/t3-oss/t3-env/llms.txt Demonstrates using Valibot presets with createEnv for environment variable validation. Includes Vercel and Railway presets. ```typescript // Using Valibot presets instead: import { createEnv } from "@t3-oss/env-core"; import { vercel, railway } from "@t3-oss/env-core/presets-valibot"; import * as v from "valibot"; export const env = createEnv({ server: { DATABASE_URL: v.pipe(v.string(), v.url()), }, extends: [vercel(), railway()], runtimeEnv: process.env, }); ``` -------------------------------- ### Using Valibot Presets Source: https://context7.com/t3-oss/t3-env/llms.txt Integrate pre-defined Valibot schema configurations using presets for common deployment environments like Vercel and Railway. ```typescript // Using Valibot presets: import { vercel, railway } from "@t3-oss/env-core/presets-valibot"; export const envWithPresets = createEnv({ server: { DATABASE_URL: v.pipe(v.string(), v.url()), }, extends: [vercel(), railway()], runtimeEnv: process.env, }); ``` -------------------------------- ### Configuring Environment Variables with Presets Source: https://context7.com/t3-oss/t3-env/llms.txt Use the extends property in createEnv to integrate platform presets and automatically type the resulting environment object. ```typescript import { createEnv } from "@t3-oss/env-nextjs"; import { vercel, neonVercel, uploadthing } from "@t3-oss/env-nextjs/presets-zod"; import * as z from "zod"; export const env = createEnv({ server: { AUTH_SECRET: z.string().min(32), }, client: { NEXT_PUBLIC_APP_URL: z.string().url(), }, experimental__runtimeEnv: { NEXT_PUBLIC_APP_URL: process.env.NEXT_PUBLIC_APP_URL, }, extends: [vercel(), neonVercel(), uploadthing()], }); // All preset variables are now typed: env.VERCEL_URL; // string | undefined env.VERCEL_ENV; // "development" | "preview" | "production" | undefined env.DATABASE_URL; // string (from neonVercel) env.UPLOADTHING_TOKEN; // string ``` -------------------------------- ### Create environment schema Source: https://github.com/t3-oss/t3-env/blob/main/docs/src/app/docs/core/page.mdx Define server and client environment variables using createEnv. Set emptyStringAsUndefined to true to handle empty strings correctly during validation. ```typescript import { createEnv } from "@t3-oss/env-core"; import * as z from "zod"; export const env = createEnv({ server: { DATABASE_URL: z.url(), OPEN_AI_API_KEY: z.string().min(1), }, /** * The prefix that client-side variables must have. This is enforced both at * a type-level and at runtime. */ clientPrefix: "PUBLIC_", client: { PUBLIC_CLERK_PUBLISHABLE_KEY: z.string().min(1), }, /** * What object holds the environment variables at runtime. This is usually * `process.env` or `import.meta.env`. */ runtimeEnv: process.env, /** * By default, this library will feed the environment variables directly to * the Zod validator. * * This means that if you have an empty string for a value that is supposed * to be a number (e.g. `PORT=` in a ".env" file), Zod will incorrectly flag * it as a type mismatch violation. Additionally, if you have an empty string * for a value that is supposed to be a string with a default value (e.g. * `DOMAIN=` in an ".env" file), the default value will never be applied. * * In order to solve these issues, we recommend that all new projects * explicitly specify this option as true. */ emptyStringAsUndefined: true, }); ``` -------------------------------- ### Checkout branch Source: https://github.com/t3-oss/t3-env/blob/main/README.md Switch to a new feature branch for development. ```sh git checkout ``` -------------------------------- ### Create Environment Schema Source: https://github.com/t3-oss/t3-env/blob/main/docs/src/app/docs/nextjs/page.mdx Define server and client environment variables using Zod. Requires manual runtimeEnv mapping for older Next.js versions. ```ts import { createEnv } from "@t3-oss/env-nextjs"; import * as z from "zod"; export const env = createEnv({ server: { DATABASE_URL: z.url(), OPEN_AI_API_KEY: z.string().min(1), }, client: { NEXT_PUBLIC_PUBLISHABLE_KEY: z.string().min(1), }, // If you're using Next.js < 13.4.4, you'll need to specify the runtimeEnv manually runtimeEnv: { DATABASE_URL: process.env.DATABASE_URL, OPEN_AI_API_KEY: process.env.OPEN_AI_API_KEY, NEXT_PUBLIC_PUBLISHABLE_KEY: process.env.NEXT_PUBLIC_PUBLISHABLE_KEY, }, // For Next.js >= 13.4.4, you only need to destructure client variables: // experimental__runtimeEnv: { // NEXT_PUBLIC_PUBLISHABLE_KEY: process.env.NEXT_PUBLIC_PUBLISHABLE_KEY, // } }); ``` -------------------------------- ### Configure createEnv for Next.js Source: https://context7.com/t3-oss/t3-env/llms.txt Use the Next.js specific package to enforce NEXT_PUBLIC_ prefixes and handle environment variable exposure via experimental__runtimeEnv or runtimeEnv. ```typescript // src/env.ts import { createEnv } from "@t3-oss/env-nextjs"; import * as z from "zod"; export const env = createEnv({ server: { DATABASE_URL: z.string().url(), SECRET_KEY: z.string().min(32), }, // Client variables must be prefixed with NEXT_PUBLIC_ client: { NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: z.string().min(1), NEXT_PUBLIC_API_URL: z.string().url(), }, shared: { NODE_ENV: z.enum(["development", "production", "test"]), }, // For Next.js >= 13.4.4: only client-side variables need manual destructuring experimental__runtimeEnv: { NODE_ENV: process.env.NODE_ENV, NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY, NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL, }, // Or for Next.js < 13.4.4: all variables need manual destructuring // runtimeEnv: { // DATABASE_URL: process.env.DATABASE_URL, // SECRET_KEY: process.env.SECRET_KEY, // NODE_ENV: process.env.NODE_ENV, // NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY, // NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL, // }, }); // src/app/api/route.ts import { env } from "../env"; export const GET = () => { // Server-side: all variables accessible const dbUrl = env.DATABASE_URL; return Response.json({ status: "ok" }); }; // src/app/page.tsx (Client Component) "use client"; import { env } from "../env"; export default function Page() { // Client-side: only NEXT_PUBLIC_ and shared variables return
API: {env.NEXT_PUBLIC_API_URL}
; } ``` -------------------------------- ### Importing Platform Presets Source: https://context7.com/t3-oss/t3-env/llms.txt Import platform-specific presets from the desired validator module to enable automatic typing for deployment environment variables. ```typescript import { vercel, // Vercel system variables (VERCEL_URL, VERCEL_ENV, etc.) neonVercel, // Neon + Vercel integration (DATABASE_URL, PGHOST, etc.) supabaseVercel, // Supabase + Vercel integration (POSTGRES_URL, SUPABASE_URL, etc.) uploadthing, // UploadThing (UPLOADTHING_TOKEN) render, // Render (RENDER_EXTERNAL_URL, RENDER_SERVICE_NAME, etc.) railway, // Railway (RAILWAY_PUBLIC_DOMAIN, RAILWAY_PROJECT_NAME, etc.) fly, // Fly.io (FLY_APP_NAME, FLY_REGION, FLY_PUBLIC_IP, etc.) netlify, // Netlify (NETLIFY, URL, DEPLOY_URL, SITE_NAME, etc.) upstashRedis, // Upstash Redis (UPSTASH_REDIS_REST_URL, UPSTASH_REDIS_REST_TOKEN) coolify, // Coolify (COOLIFY_URL, COOLIFY_BRANCH, etc.) vite, // Vite (BASE_URL, MODE, DEV, PROD, SSR) wxt, // WXT browser extension (MANIFEST_VERSION, BROWSER, etc.) } from "@t3-oss/env-core/presets-zod"; ``` -------------------------------- ### Use T3 Env Presets Source: https://github.com/t3-oss/t3-env/blob/main/docs/src/app/docs/standard-schema/page.mdx Extend environment configuration using platform-specific presets. ```ts import { createEnv } from "@t3-oss/env-core"; import { vercel } from "@t3-oss/env-core/presets-valibot"; import * as v from "valibot"; export const env = createEnv({ server: { DATABASE_URL: v.pipe(v.string(), v.url()), }, extends: [vercel()], runtimeEnv: process.env, }); ``` -------------------------------- ### Define environment schema Source: https://github.com/t3-oss/t3-env/blob/main/README.md Configure environment variables using createEnv with Zod validation for server and client scopes. ```ts // src/env.mjs import { createEnv } from "@t3-oss/env-nextjs"; // or core package import * as z from "zod"; export const env = createEnv({ /* * Serverside Environment variables, not available on the client. * Will throw if you access these variables on the client. */ server: { DATABASE_URL: z.url(), OPEN_AI_API_KEY: z.string().min(1), }, /* * Environment variables available on the client (and server). * * 💡 You'll get type errors if these are not prefixed with NEXT_PUBLIC_. */ client: { NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: z.string().min(1), }, /* * Due to how Next.js bundles environment variables on Edge and Client, * we need to manually destructure them to make sure all are included in bundle. * * 💡 You'll get type errors if not all variables from `server` & `client` are included here. */ 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, }, }); ``` -------------------------------- ### Configure createEnv with Core Package Source: https://context7.com/t3-oss/t3-env/llms.txt Define server, client, and shared environment variables using Zod schemas. The runtimeEnv property maps the actual environment variables to the schema. ```typescript // src/env.ts import { createEnv } from "@t3-oss/env-core"; import * as z from "zod"; export const env = createEnv({ // Server-side variables - will throw if accessed on client server: { DATABASE_URL: z.string().url(), OPEN_AI_API_KEY: z.string().min(1), PORT: z.coerce.number().default(3000), }, // Client-side variables - must have the specified prefix clientPrefix: "PUBLIC_", client: { PUBLIC_API_URL: z.string().url(), PUBLIC_CLERK_PUBLISHABLE_KEY: z.string().min(1), }, // Shared variables - available on both server and client shared: { NODE_ENV: z.enum(["development", "production", "test"]), }, // Runtime environment object runtimeEnv: process.env, }); // Usage - fully typed with autocompletion console.log(env.DATABASE_URL); // string (URL) console.log(env.PORT); // number (coerced, defaults to 3000) console.log(env.PUBLIC_API_URL); // string (URL) console.log(env.NODE_ENV); // "development" | "production" | "test" // Type error: Property 'UNDEFINED_VAR' does not exist // env.UNDEFINED_VAR; // Runtime error on client: "Attempted to access a server-side environment variable on the client" // (when accessed in browser context) // env.DATABASE_URL; ``` -------------------------------- ### Define Environment Schemas Source: https://github.com/t3-oss/t3-env/blob/main/packages/nuxt/README.md Configure server and client environment variables using Zod validation. ```ts // src/env.ts import { createEnv } from "@t3-oss/env-nuxt"; import * as z from "zod"; export const env = createEnv({ /* * Serverside Environment variables, not available on the client. * Will throw if you access these variables on the client. */ server: { DATABASE_URL: z.url(), OPEN_AI_API_KEY: z.string().min(1), }, /* * Environment variables available on the client (and server). * * 💡 You'll get type errors if these are not prefixed with NUXT_PUBLIC_. */ client: { NUXT_PUBLIC_CLERK_PUBLISHABLE_KEY: z.string().min(1), }, }); ``` -------------------------------- ### Extending Presets with Zod for Next.js Source: https://context7.com/t3-oss/t3-env/llms.txt Extend createEnv with platform presets like Vercel, Uploadthing, and Upstash Redis for Next.js applications. Automatically validates and exposes system environment variables. ```typescript // src/env.ts import { createEnv } from "@t3-oss/env-nextjs"; import { vercel, uploadthing, upstashRedis } from "@t3-oss/env-nextjs/presets-zod"; import * as z from "zod"; export const env = createEnv({ server: { DATABASE_URL: z.string().url(), }, client: { NEXT_PUBLIC_APP_URL: z.string().url(), }, experimental__runtimeEnv: { NEXT_PUBLIC_APP_URL: process.env.NEXT_PUBLIC_APP_URL, }, // Extend with platform presets extends: [vercel(), uploadthing(), upstashRedis()] }); // Now you have typed access to all extended variables: env.VERCEL_URL; // string | undefined env.VERCEL_ENV; // "development" | "preview" | "production" | undefined env.UPLOADTHING_TOKEN; // string env.UPSTASH_REDIS_REST_URL; // string env.UPSTASH_REDIS_REST_TOKEN; // string ``` -------------------------------- ### Configure Environment Variables with Zod Source: https://github.com/t3-oss/t3-env/blob/main/packages/nextjs/README.md Define server and client environment variables using Zod schemas and the createEnv function. ```typescript // src/env.ts import { createEnv } from "@t3-oss/env-nextjs"; import * as z from "zod"; export const env = createEnv({ /* * Serverside Environment variables, not available on the client. * Will throw if you access these variables on the client. */ server: { DATABASE_URL: z.url(), OPEN_AI_API_KEY: z.string().min(1), }, /* * Environment variables available on the client (and server). * * 💡 You'll get type errors if these are not prefixed with NEXT_PUBLIC_. */ client: { NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: z.string().min(1), }, /* * Specify what values should be validated by your schemas above. * * If you're using Next.js < 13.4.4, you'll need to specify the runtimeEnv manually * For Next.js >= 13.4.4, you can use the experimental__runtimeEnv option and * only specify client-side variables. */ runtimeEnv: { DATABASE_URL: process.env.DATABASE_URL, OPEN_AI_API_KEY: process.env.OPEN_AI_API_KEY, NEXT_PUBLIC_PUBLISHABLE_KEY: process.env.NEXT_PUBLIC_PUBLISHABLE_KEY, }, // experimental__runtimeEnv: { // NEXT_PUBLIC_PUBLISHABLE_KEY: process.env.NEXT_PUBLIC_PUBLISHABLE_KEY, // } }); ``` -------------------------------- ### Configure Standalone Output Source: https://github.com/t3-oss/t3-env/blob/main/docs/src/app/docs/nextjs/page.mdx Required configuration for standalone output mode in next.config.ts to ensure proper transpilation. ```ts import type { NextConfig } from "next" const nextConfig: NextConfig = { output: "standalone", // Add the packages in transpilePackages transpilePackages: ["@t3-oss/env-nextjs", "@t3-oss/env-core"], } export default nextConfig ``` -------------------------------- ### CreateEnv for Nuxt Source: https://context7.com/t3-oss/t3-env/llms.txt Use createEnv with Nuxt to automatically fill runtimeEnv from process.env. Enforces NUXT_PUBLIC_ prefix for client-accessible variables. ```typescript // src/env.ts import { createEnv } from "@t3-oss/env-nuxt"; import * as z from "zod"; export const env = createEnv({ server: { DATABASE_URL: z.string().url(), OPEN_AI_API_KEY: z.string().min(1), }, // Client variables must be prefixed with NUXT_PUBLIC_ client: { NUXT_PUBLIC_CLERK_PUBLISHABLE_KEY: z.string().min(1), NUXT_PUBLIC_APP_URL: z.string().url(), }, // No runtimeEnv needed - automatically uses process.env }); // pages/index.vue ``` -------------------------------- ### Define environment schema Source: https://github.com/t3-oss/t3-env/blob/main/docs/src/app/docs/nuxt/page.mdx Create a schema file to validate server and client environment variables. ```typescript import { createEnv } from "@t3-oss/env-nuxt"; import * as z from "zod"; export const env = createEnv({ server: { DATABASE_URL: z.url(), OPEN_AI_API_KEY: z.string().min(1), }, client: { NUXT_PUBLIC_PUBLISHABLE_KEY: z.string().min(1), }, }); ``` -------------------------------- ### Extend T3 Env with Vercel Preset (Zod) Source: https://github.com/t3-oss/t3-env/blob/main/docs/src/app/docs/customization/page.mdx Extend T3 Env with the Vercel preset using `extends: [vercel()]`. This is useful for including system environment variables provided by Vercel. ```typescript import { createEnv } from "@t3-oss/env-core"; import { vercel } from "@t3-oss/env-core/presets-zod"; export const env = createEnv({ // ... // Extend the Vercel preset. extends: [vercel()], }); env.VERCEL_URL; // string ``` -------------------------------- ### Access Publishable Key on Client Source: https://github.com/t3-oss/t3-env/blob/main/docs/src/app/docs/nextjs/page.mdx The same `env` object import works on the client-side to access public environment variables, such as `PUBLIC_PUBLISHABLE_KEY`, for initializing client-side SDKs. ```typescript import { env } from "~/env"; // On client - same import! export const SomeComponent = () => { return ( {/* ... */} ); }; ``` -------------------------------- ### Clone repository Source: https://github.com/t3-oss/t3-env/blob/main/README.md Clone the T3 Env source code from GitHub. ```sh git clone https://github.com/t3-oss/t3-env.git ``` -------------------------------- ### Access OpenAI API Key on Server Source: https://github.com/t3-oss/t3-env/blob/main/docs/src/app/docs/nextjs/page.mdx Import the `env` object to access server-side environment variables like `OPEN_AI_API_KEY` for making authenticated API requests. ```typescript import { env } from "~/env"; // On server export const GET = async () => { // do fancy ai stuff const magic = await fetch("...", { headers: { Authorization: env.OPEN_AI_API_KEY }, }); // ... }; ``` -------------------------------- ### Custom Preset for Monorepo Shared Config Source: https://context7.com/t3-oss/t3-env/llms.txt Define a custom preset for shared environment variables across monorepo packages using createEnv. Shows separate configurations for auth and web packages. ```typescript // Custom preset for monorepo shared config: // packages/auth/env.ts import { createEnv } from "@t3-oss/env-core"; import * as z from "zod"; export const authEnv = createEnv({ server: { AUTH_SECRET: z.string().min(32), AUTH_URL: z.string().url(), }, runtimeEnv: process.env, }); // apps/web/env.ts import { createEnv } from "@t3-oss/env-nextjs"; import { authEnv } from "@repo/auth/env"; export const env = createEnv({ server: { DATABASE_URL: z.string().url() }, extends: [authEnv], // ... }); ``` -------------------------------- ### Validate Schema on Build Source: https://github.com/t3-oss/t3-env/blob/main/docs/src/app/docs/nextjs/page.mdx Import the environment schema into next.config to enforce validation during the build process. ```ts import "./app/env"; /** @type {import('next').NextConfig} */ const nextConfig: NextConfig = { /** ... */ }; export default nextConfig; ``` ```js import { createJiti } from 'jiti'; const jiti = createJiti(import.meta.url); // Import env here to validate during build. Using jiti@^1 we can import .ts files :) await jiti.import('./app/env'); /** @type {import('next').NextConfig} */ export default { /** ... */ }; ``` -------------------------------- ### Refine Schemas with createFinalSchema Source: https://github.com/t3-oss/t3-env/blob/main/docs/src/app/docs/customization/page.mdx Apply custom transformations and validation logic to the final environment object using Zod. ```typescript import { createEnv } from "@t3-oss/env-core"; import * as z from "zod"; export const env = createEnv({ server: { SKIP_AUTH: z.boolean().optional(), EMAIL: z.string().email().optional(), PASSWORD: z.string().min(1).optional(), }, // ... createFinalSchema: (shape, isServer) => z.object(shape).transform((env, ctx) => { if (env.SKIP_AUTH || !isServer) return { SKIP_AUTH: true } as const; if (!env.EMAIL || !env.PASSWORD) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: "EMAIL and PASSWORD are required if SKIP_AUTH is false", }); return z.NEVER; } return { EMAIL: env.EMAIL, PASSWORD: env.PASSWORD, }; }), }); ``` -------------------------------- ### Configure T3 Env with Zod Source: https://github.com/t3-oss/t3-env/blob/main/docs/src/app/docs/standard-schema/page.mdx Define environment variables using Zod schemas. ```ts import { createEnv } from "@t3-oss/env-core"; import * as z from "zod"; export const env = createEnv({ server: { DATABASE_URL: z.string().url(), PORT: z.coerce.number().default(3000), }, clientPrefix: "PUBLIC_", client: { PUBLIC_API_URL: z.string().url(), }, runtimeEnv: process.env, }); ``` -------------------------------- ### Split Environment Schemas Source: https://github.com/t3-oss/t3-env/blob/main/docs/src/app/docs/nextjs/page.mdx Separate server and client schemas to prevent sensitive variable names from being shipped to the client bundle. ```ts import { createEnv } from "@t3-oss/env-nextjs"; import * as z from "zod"; export const env = createEnv({ server: { DATABASE_URL: z.url(), OPEN_AI_API_KEY: z.string().min(1), }, // If you're using Next.js < 13.4.4, you'll need to specify the runtimeEnv manually // runtimeEnv: { // DATABASE_URL: process.env.DATABASE_URL, // OPEN_AI_API_KEY: process.env.OPEN_AI_API_KEY, // }, // For Next.js >= 13.4.4, you can just reference process.env: experimental__runtimeEnv: process.env }); ``` ```ts import { createEnv } from "@t3-oss/env-nextjs"; import * as z from "zod"; export const env = createEnv({ client: { NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: z.string().min(1), }, runtimeEnv: { NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY, }, }); ``` -------------------------------- ### Configure T3 Env with Runtime Strictness Source: https://github.com/t3-oss/t3-env/blob/main/docs/src/app/docs/core/page.mdx Configure T3 Env with `runtimeEnvStrict` to ensure all declared server and client environment variables are explicitly accessed at runtime. This prevents accidental omission of required variables. ```typescript import { createEnv } from "@t3-oss/env-core"; export const env = createEnv({ clientPrefix: "PUBLIC_", server: { DATABASE_URL: z.url(), OPEN_AI_API_KEY: z.string().min(1), }, client: { PUBLIC_PUBLISHABLE_KEY: z.string().min(1), }, /** * Makes sure you explicitly access **all** environment variables * from `server` and `client` in your `runtimeEnv`. */ runtimeEnvStrict: { DATABASE_URL: process.env.DATABASE_URL, OPEN_AI_API_KEY: process.env.OPEN_AI_API_KEY, PUBLIC_PUBLISHABLE_KEY: process.env.PUBLIC_PUBLISHABLE_KEY, }, }); ``` -------------------------------- ### Split server and client schemas Source: https://github.com/t3-oss/t3-env/blob/main/docs/src/app/docs/core/page.mdx Separate server and client schemas into different files to prevent sensitive variable names from being shipped to the client. ```typescript import { createEnv } from "@t3-oss/env-core"; import * as z from "zod"; export const env = createEnv({ server: { DATABASE_URL: z.url(), OPEN_AI_API_KEY: z.string().min(1), }, runtimeEnv: process.env, }); ``` ```typescript import { createEnv } from "@t3-oss/env-core"; import * as z from "zod"; export const env = createEnv({ clientPrefix: "PUBLIC_", client: { PUBLIC_CLERK_PUBLISHABLE_KEY: z.string().min(1), }, runtimeEnv: process.env, }); ``` -------------------------------- ### Configure T3 Env with Valibot Source: https://github.com/t3-oss/t3-env/blob/main/docs/src/app/docs/standard-schema/page.mdx Define environment variables using Valibot schemas. ```ts import { createEnv } from "@t3-oss/env-core"; import * as v from "valibot"; export const env = createEnv({ server: { DATABASE_URL: v.pipe(v.string(), v.url()), PORT: v.optional(v.pipe(v.string(), v.transform(Number)), "3000"), }, clientPrefix: "PUBLIC_", client: { PUBLIC_API_URL: v.pipe(v.string(), v.url()), }, runtimeEnv: process.env, }); ``` -------------------------------- ### Specify Server Context in T3 Env Source: https://github.com/t3-oss/t3-env/blob/main/docs/src/app/docs/customization/page.mdx Use the `isServer` option to explicitly tell T3 Env whether it's running in a server context. This is typically determined by checking for the absence of `window`. ```typescript import { createEnv } from "@t3-oss/env-core"; export const env = createEnv({ // ... // Tell the library when we're in a server context. isServer: typeof window === "undefined", }); ``` -------------------------------- ### Split environment schemas Source: https://github.com/t3-oss/t3-env/blob/main/docs/src/app/docs/nuxt/page.mdx Separate server and client schemas to prevent sensitive variable names from being exposed to the client. ```typescript import { createEnv } from "@t3-oss/env-nuxt"; import * as z from "zod"; export const env = createEnv({ server: { DATABASE_URL: z.url(), OPEN_AI_API_KEY: z.string().min(1), }, }); ``` ```typescript import { createEnv } from "@t3-oss/env-nuxt"; import * as z from "zod"; export const env = createEnv({ client: { PUBLIC_CLERK_PUBLISHABLE_KEY: z.string().min(1), }, }); ``` -------------------------------- ### Configure T3 Env with ArkType Source: https://github.com/t3-oss/t3-env/blob/main/docs/src/app/docs/standard-schema/page.mdx Define environment variables using ArkType schemas. ```ts import { createEnv } from "@t3-oss/env-core"; import { type } from "arktype"; export const env = createEnv({ server: { DATABASE_URL: type("string.url"), PORT: type("string.numeric.parse"), }, clientPrefix: "PUBLIC_", client: { PUBLIC_API_URL: type("string.url"), }, runtimeEnv: process.env, }); ``` -------------------------------- ### Validate environment variables with Zod Source: https://github.com/t3-oss/t3-env/blob/main/docs/src/app/docs/introduction/page.mdx A basic implementation using Zod to validate environment variables and extend the global NodeJS ProcessEnv interface. ```ts import * as z from "zod"; const envVariables = z.object({ DATABASE_URL: z.string(), CUSTOM_STUFF: z.string(), }); envVariables.parse(process.env); declare global { namespace NodeJS { interface ProcessEnv extends z.infer {} } } ``` -------------------------------- ### Treat Empty Strings as Undefined Source: https://context7.com/t3-oss/t3-env/llms.txt Enable emptyStringAsUndefined to treat empty environment variables as undefined, allowing Zod default values to take effect. ```typescript // src/env.ts import { createEnv } from "@t3-oss/env-core"; import * as z from "zod"; export const env = createEnv({ server: { // Without emptyStringAsUndefined: PORT="" would fail z.coerce.number() // With emptyStringAsUndefined: PORT="" becomes undefined, default 3000 applies PORT: z.coerce.number().default(3000), // Without: DOMAIN="" would be "", not "localhost" // With: DOMAIN="" becomes undefined, default "localhost" applies DOMAIN: z.string().default("localhost"), // Required field - empty string would fail validation DATABASE_URL: z.string().url(), }, runtimeEnv: process.env, // Treat empty strings as undefined emptyStringAsUndefined: true, }); // .env file: // PORT= // DOMAIN= // DATABASE_URL=postgres://localhost/db // Result: // env.PORT === 3000 (default applied) // env.DOMAIN === "localhost" (default applied) // env.DATABASE_URL === "postgres://localhost/db" ``` -------------------------------- ### Integrate t3-env with Storybook Source: https://github.com/t3-oss/t3-env/blob/main/docs/src/app/docs/recipes/page.mdx Ensure environment variables are available in Storybook by merging `t3Env` with Storybook's config using the `env` property in `.storybook/main.ts`. This is necessary because Storybook's bundler does not automatically call `runtimeEnv`. ```typescript // .storybook/main.ts import { env as t3Env } from "~/env/client.mjs"; const config: StorybookConfig = { // other Storybook config... env: (config1) => ({ ...config1, ...t3Env, }) }; export default config; ``` -------------------------------- ### Extend Environment Schemas Source: https://github.com/t3-oss/t3-env/blob/main/docs/src/app/docs/customization/page.mdx Use the extends property to merge environment configurations from different packages or modules. ```typescript // packages/auth/env.ts import { createEnv } from "@t3-oss/env-core"; export const env = createEnv({ // ... }); // apps/web/env.ts import { createEnv } from "@t3-oss/env-nextjs"; import { env as authEnv } from "@repo/auth/env"; export const env = createEnv({ // ... extends: [authEnv], }); ``` -------------------------------- ### Implement Boolean and Number Coercion Source: https://context7.com/t3-oss/t3-env/llms.txt Transform string-based environment variables into booleans, numbers, arrays, or objects using Zod's transformation and coercion utilities. ```typescript // src/env.ts import { createEnv } from "@t3-oss/env-core"; import * as z from "zod"; export const env = createEnv({ server: { // Boolean coercion - custom transform (recommended) ENABLE_FEATURE: z .string() .transform((s) => s !== "false" && s !== "0"), // Boolean - strict validation STRICT_BOOLEAN: z .string() .refine((s) => s === "true" || s === "false") .transform((s) => s === "true"), // Zod v4 stringbool (if available) // ZOD_V4_BOOL: z.stringbool(), // Number coercion - using Zod coerce PORT: z.coerce.number().min(1).max(65535), // Number - manual transform with validation MAX_CONNECTIONS: z .string() .transform((s) => parseInt(s, 10)) .pipe(z.number().positive()), // Number with default TIMEOUT_MS: z.coerce.number().default(5000), // Comma-separated list to array ALLOWED_ORIGINS: z .string() .transform((s) => s.split(",").map((origin) => origin.trim())) .pipe(z.array(z.string().url())), // JSON string to object CONFIG_JSON: z .string() .transform((s) => JSON.parse(s)) .pipe(z.object({ key: z.string(), value: z.number() })), }, runtimeEnv: process.env, emptyStringAsUndefined: true, }); // .env file: // ENABLE_FEATURE=true // STRICT_BOOLEAN=false // PORT=3000 // MAX_CONNECTIONS=100 // ALLOWED_ORIGINS=https://example.com,https://api.example.com // CONFIG_JSON={"key":"test","value":42} // Usage: env.ENABLE_FEATURE; // true (boolean) env.STRICT_BOOLEAN; // false (boolean) env.PORT; // 3000 (number) env.MAX_CONNECTIONS; // 100 (number) env.ALLOWED_ORIGINS; // ["https://example.com", "https://api.example.com"] env.CONFIG_JSON; // { key: "test", value: 42 } ``` -------------------------------- ### Custom Error Handling for Validation and Access Source: https://context7.com/t3-oss/t3-env/llms.txt Override default error handlers in createEnv for custom validation error reporting and handling invalid server variable access on the client. ```typescript // src/env.ts import { createEnv, type StandardSchemaV1 } from "@t3-oss/env-core"; import * as z from "zod"; export const env = createEnv({ server: { DATABASE_URL: z.string().url(), API_KEY: z.string().min(1), }, clientPrefix: "PUBLIC_", client: { PUBLIC_APP_URL: z.string().url(), }, runtimeEnv: process.env, // Custom validation error handler onValidationError: (issues: readonly StandardSchemaV1.Issue[]) => { console.error("Environment validation failed:"); issues.forEach((issue) => { console.error(` - ${issue.path?.join(".")}: ${issue.message}`); }); // Report to error tracking service // errorTracker.captureException(new Error("Invalid environment variables")); throw new Error( `Invalid environment variables: ${issues.map((i) => i.path?.join(".")).join(", ")}` ); }, // Custom handler for accessing server vars on client onInvalidAccess: (variable: string) => { console.error(`Attempted to access server variable "${variable}" on client`); throw new Error( `Security Error: Cannot access "${variable}" in browser context` ); }, }); ``` -------------------------------- ### Access environment variables Source: https://github.com/t3-oss/t3-env/blob/main/README.md Import the validated env object to access environment variables with full type inference. ```ts // src/app/hello/route.ts import { env } from "../env.mjs"; export const GET = (req: Request) => { const DATABASE_URL = env.DATABASE_URL; // use it... }; ``` -------------------------------- ### Validate schema in nuxt.config.ts Source: https://github.com/t3-oss/t3-env/blob/main/docs/src/app/docs/nuxt/page.mdx Import the schema file in nuxt.config.ts to ensure environment variables are validated at build time. ```typescript import "./env"; export default defineNuxtConfig({ // ... }); ``` -------------------------------- ### Access environment variables Source: https://github.com/t3-oss/t3-env/blob/main/docs/src/app/docs/nuxt/page.mdx Import the validated env object to access environment variables with type safety on both server and client. ```typescript import { env } from "~~/env"; // On server export default defineEventHandler(() => { // do fancy ai stuff const magic = await fetch("...", { headers: { Authorization: env.OPEN_AI_API_KEY }, }); // ... }); ``` ```typescript ``` -------------------------------- ### Coerce Numbers from Strings with t3-env and Zod Source: https://github.com/t3-oss/t3-env/blob/main/docs/src/app/docs/recipes/page.mdx Transform strings to numbers using `z.string().transform(parseInt)` or leverage Zod's built-in `z.coerce.number()` for primitive coercion. Always pipe with `z.number()` to ensure the transform was successful. ```typescript export const env = createEnv({ server: { SOME_NUMBER: z .string() // transform to number .transform((s) => parseInt(s, 10)) // make sure transform worked .pipe(z.number()), // Alternatively, use Zod's default primitives coercion // https://zod.dev/?id=coercion-for-primitives ZOD_NUMBER_COERCION: z.coerce.number(), }, // ... }); ```