In this article, we analyse the ClientOptions interface provided for the client object in createEnv parameter, a function in T3 Env. A simple usage of t3-env is provided below:
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,
},
});
We are interested in finding out the types/interfaces of client object.
client: {
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: z.string().min(1),
},
Straight away, I could tell we could expect this type along the lines of Record<String, ZodType>, but the way t3-env defines is different. Look at the below type picked from T3 Env source code.
export interface ClientOptions<
TPrefix extends string | undefined,
TClient extends Record<string, ZodType>,
> {
/**
* The prefix that client-side variables must have. This is enforced both at
* a type-level and at runtime.
*/
clientPrefix: TPrefix;
/**
* Specify your client-side environment variables schema here. This way you can ensure the app isn't
* built with invalid env vars.
*/
client: Partial<{
[TKey in keyof TClient]: TKey extends `${TPrefix}${string}`
? TClient[TKey]
: ErrorMessage<`${TKey extends string
? TKey
: never} is not prefixed with ${TPrefix}.`>;
}>;
}
You will find that this uses generic type and TClient is of type Record<string, ZodType>, but client does not have this type, instead it has a check in place to ensure your key defined in client is prefixed with whatever you define in ClientPrefix.
Say, for example, you have defined your prefix as “NEXT_PUBLIC_” and you try to define some variable with a key that is not prefixed with “NEXT_PBULIC_”, you will see an error along the lines “{variable} is not prefixed with “NEXT_PBULIC_”
This is powerful in frameworks like Next.js where you don’t want to accidentally expose server side varaibles to the client side.
Check this docs — https://env.t3.gg/docs/core#create-your-schema, this talks about prefix error.
About me:
Hey, my name is Ramu Narasinga. I study large open-source projects and create content about their codebase architecture and best practices, sharing it through articles, videos.
I am open to work on an interesting project. Send me an email at ramu.narasinga@gmail.com
My Github - https://github.com/ramu-narasinga
My website - https://ramunarasinga.com
My Youtube channel - https://www.youtube.com/@thinkthroo
Learning platform - https://thinkthroo.com
Codebase Architecture - https://app.thinkthroo.com/architecture
Best practices - https://app.thinkthroo.com/best-practices
Production-grade projects - https://app.thinkthroo.com/production-grade-projects
Top comments (0)