t3-env

repository·main·Indexed 26 days ago

https://github.com/t3-oss/t3-env

A library for creating typesafe environment variable schemas to prevent application deployment with invalid or missing variables. It supports framework-agnostic usage via @t3-oss/env-core, as well as dedicated packages for Next.js (@t3-oss/env-nextjs) and Nuxt (@t3-oss/env-nuxt). t3-env works with any Standard Schema compliant validator such as Zod, Valibot, or ArkType, and allows for the separation of server-side and client-side environment variables.

Tokens
16.3K
Snippets
52
Records
78
Agent score
85%

What's inside t3-env

  1. Overview of T3 Env features

    main

    T3 Env is a library designed to provide type-safe environment variable validation for your applications. It simplifies the process of ensuring required environment variables are present and correctly typed during build or runtime.

    Key features include:

    • Type-safe environment variables: Provides autocomplete and type checking for your environment variables.
    • Standard Schema support: Compatible with any Standard Schema compliant validator such as Zod, Valibot, ArkType, or Typia.
    • Server/Client separation: Prevents accidental exposure of server-side environment variables to the client by throwing descriptive errors if they are accessed in a client context.
    • Framework agnostic: Supports Next.js, Nuxt, Vite, and other frameworks.
    • Presets included: Offers ready-to-use configurations for platforms like Vercel, Netlify, and Railway.
  2. Advantages of T3 Env over manual Zod validation

    main

    While you can manually validate process.env using Zod and augment the NodeJS.ProcessEnv interface, T3 Env solves several critical issues:

    Transforms and Default values

    Manual validation of process.env does not mutate the original object. If you apply transforms (e.g., converting a string to a number), your TypeScript types will reflect the transformed type, but process.env will still contain the original string, leading to type lies. T3 Env provides an object you import that correctly holds both transformed values and default values.

    Support for multiple environments

    Some frameworks (like Next.js) tree-shake unused environment variables. Simply exporting a validation object might not be enough to ensure variables are included in the bundle. T3 Env uses a Proxy-based implementation to ensure variables are correctly handled across different runtimes.

    Client-side safety

    Importing a global validation object on the client often causes errors because server-only variables (like DATABASE_URL) are undefined in the browser. T3 Env prevents leaking server variables to the client and provides descriptive error messages when an attempt is made to access a server-only variable in a client context.

  3. Install @t3-oss/env-nuxt

    main

    Install the Nuxt package using your preferred package manager to enable typesafe environment variables in your Nuxt application.

    # 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
  4. Use @t3-oss/env-nuxt to define environment schemas

    main

    Use createEnv from @t3-oss/env-nuxt to define your environment variable schemas. This package is preconfigured for Nuxt and automatically fills the runtimeEnv option.

    Supported schema types:

    • server: Variables available only on the server side. Accessing these on the client will throw an error.
    • client: Variables available on both the client and the server. Note: Client variables must be prefixed with NUXT_PUBLIC_ to avoid type errors.

    You can use any Standard Schema compliant validator (e.g., Zod, Valibot, ArkType).

    // 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),
      },
    });
  5. Validate environment variables at build time

    main

    To catch missing environment variables during the build process, import your env configuration file inside your next.config file.

    • For Next.js 16+: You can import the .ts file directly.
    • For Next.js < 16: Use jiti to import the .ts file in your next.config.js.
    import "./app/env";
    
    /** @type {import('next').NextConfig} */
    const nextConfig = {
      /** ... */
    };
    
    export default nextConfig;
    import { createJiti } from 'jiti';
    
    const jiti = createJiti(import.meta.url);
    
    // Import env here to validate during build.
    await jiti.import('./app/env');
    
    /** @type {import('next').NextConfig} */
    export default {
      /** ... */
    };
  6. Install @t3-oss/env-nuxt

    main

    To use T3 Env with Nuxt, install the @t3-oss/env-nuxt package along with a validator like zod. Note that @t3-oss/env-core (a dependency) requires typescript@5 and is an ESM-only package. Ensure your tsconfig uses a module resolution that supports package.json#exports (e.g., Bundler).

    pnpm add @t3-oss/env-nuxt zod
    
    # or using JSR
    deno add jsr:@t3-oss/env-nuxt
  7. Define an environment schema with createEnv

    main

    Use createEnv to define your environment variable schema. You can use any Standard Schema compliant validator (like Zod or Valibot).

    • server: Variables available only on the server. Accessing these on the client will throw an error.
    • client: Variables available on both client and server. In Next.js, these must be prefixed with NEXT_PUBLIC_.
    • runtimeEnv: A mapping of the actual process.env values. You must manually destructure all variables from server and client here to ensure they are included in bundles (especially for Edge or Client runtimes).
    // 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,
      },
    });
  8. Install @t3-oss/env-core

    main

    Install the framework-agnostic core package and a validator (e.g., Zod).

    Requirements:

    • typescript@5.0.0 or higher.
    • An ESM-only compatible tsconfig (using Bundler module resolution is recommended).

    Note: While Zod is used in examples, you can use any validator that supports Standard Schema, such as Valibot, ArkType, or Typia.

    npm install @t3-oss/env-core zod
    
    # or using JSR
    deno add jsr:@t3-oss/env-core
  9. Create an environment schema with @t3-oss/env-nuxt

    main

    Define your environment variables using createEnv. You can define both server and client schemas in a single file for the best developer experience. However, if variable names are sensitive, split them into separate files (e.g., server.ts and client.ts) to prevent server-only variable names from being shipped to the client.

    Supported validators must follow the Standard Schema specification.

    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),
      },
    });
  10. Extend environment variable presets

    main

    You can include predefined sets of environment variables (like Vercel or Railway) using the extends property. This is useful for monorepos or deployment-specific variables.

    Available Validators

    To optimize bundle size, import the preset from the entrypoint matching your validator:

    • @t3-oss/env-core/presets-zod
    • @t3-oss/env-core/presets-valibot
    • @t3-oss/env-core/presets-arktype

    Available Presets

    • vercel
    • neonVercel
    • supabaseVercel
    • uploadthing
    • render
    • railway
    • fly.io
    • netlify
    • upstashRedis
    • coolify
    • vite
    • wxt

    You can also extend your own custom env objects.

    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,
    });