Blog
EnvOptions type in T3 Env source code explained

EnvOptions type in T3 Env source code explained

In this article, we are going to examine the EnvOptions type in T3 Env source code. In case you are wondering what’s T3 Env or EnvOptions,
T3 Env provides validation for type-safe environment variables using zod. you use createEnv function and provide zod validation for your server and client env variables as shown in below example.

// src/env.mjs
import { createEnv } from "@t3-oss/env-nextjs";
import { 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.string().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,
 },
});

This createEnv has the below type shown defined in T3 Env source code:

export function createEnv<
 TPrefix extends TPrefixFormat,
 TServer extends TServerFormat = NonNullable<unknown>,
 TClient extends TClientFormat = NonNullable<unknown>,
 TShared extends TSharedFormat = NonNullable<unknown>,
 const TExtends extends TExtendsFormat = [],
>(
 opts: EnvOptions<TPrefix, TServer, TClient, TShared, TExtends>,
): CreateEnv<TServer, TClient, TShared, TExtends> {
 const runtimeEnv = opts.runtimeEnvStrict ?? opts.runtimeEnv ?? process.env;

Function parameter here is opts with type EnvOptions<TPrefix, TServer, TClient, TShared, TExtends>

export type EnvOptions<
 TPrefix extends string | undefined,
 TServer extends Record<string, ZodType>,
 TClient extends Record<string, ZodType>,
 TShared extends Record<string, ZodType>,
 TExtends extends Array<Record<string, unknown>>,
> =
 | (LooseOptions<TShared, TExtends> &
 ServerClientOptions<TPrefix, TServer, TClient>)
 | (StrictOptions<TPrefix, TServer, TClient, TShared, TExtends> &
 ServerClientOptions<TPrefix, TServer, TClient>);

EnvOptions is a generic type. Server object in opts passed has the generic type — TServer extends Record<string, ZodType>

// server type is TServer that is a Record with key being string 
// and value being ZodType
server: {
 DATABASE_URL: z.string().url(),
 OPEN_AI_API_KEY: z.string().min(1),
},
// client type is TClient that is a Record with key being string 
// and value being ZodType
client: {
 NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: z.string().min(1),
},

I barely scratched the surface here, this feels like an advanced Typescript usecase as this EnvOptions type returns:

| (LooseOptions<TShared, TExtends> &
 ServerClientOptions<TPrefix, TServer, TClient>)
| (StrictOptions<TPrefix, TServer, TClient, TShared, TExtends> &
 ServerClientOptions<TPrefix, TServer, TClient>);

Check out the LooseOptions and ServerClientOptions in t3-env source code.

About us:

At Thinkthroo, we study large open source projects and provide architectural guides. We have developed reusable Components, built with tailwind, that you can use in your project. We offer Next.js, React and Node development services.

Book a meeting with us to discuss your project.

References:

1. https://github.com/t3-oss/t3-env/blob/main/packages/core/src/index.ts#L222
2. https://github.com/t3-oss/t3-env/blob/main/packages/core/src/index.ts#L183
3. https://env.t3.gg/