GitHub

Recipes

t3-env supports Standard Schema compliant validators, meaning you can use transforms, default values, and all the powerful features your chosen validator provides. Below we'll look at a few example recipes for common use cases.

💡

All environment variables are strings, so your schema should start with a string validator before applying transforms or coercions.

Booleans

Coercing booleans from strings is a common use case. Below are examples of how to do this with different validators.

⚠️

Zod's default primitives coercion should not be used for booleans, since every string gets coerced to true.

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

Numbers

Coercing numbers from strings is another common use case.

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

Storybook

Storybook uses its own bundler, which is otherwise unaware of t3-env and won't call into runtimeEnv to ensure that the environment variables are present. You can use Storybook's support for defining environment variables separately to ensure that all environment variables are actually available for Storybook:

// .storybook/main.ts
 
import { env as t3Env } from "~/env/client.mjs";
 
const config: StorybookConfig = {
  // other Storybook config...
  env: (config1) => ({
    ...config1,
    ...t3Env,
  })
};
 
export default config;
// .storybook/main.ts
 
import { env as t3Env } from "~/env/client.mjs";
 
const config: StorybookConfig = {
  // other Storybook config...
  env: (config1) => ({
    ...config1,
    ...t3Env,
  })
};
 
export default config;