T
TanStack12h ago
optimistic-gold

Using zod to parse environment

In the docs there is a runtime validation example in https://tanstack.com/start/latest/docs/framework/react/environment-variables#runtime-validation
// src/config/env.ts
import { z } from 'zod'
const envSchema = z.object({
DATABASE_URL: z.string().url(),
})
const clientEnvSchema = z.object({
VITE_APP_NAME: z.string(),
})
export const serverEnv = envSchema.parse(process.env)
export const clientEnv = clientEnvSchema.parse(import.meta.env)
// src/config/env.ts
import { z } from 'zod'
const envSchema = z.object({
DATABASE_URL: z.string().url(),
})
const clientEnvSchema = z.object({
VITE_APP_NAME: z.string(),
})
export const serverEnv = envSchema.parse(process.env)
export const clientEnv = clientEnvSchema.parse(import.meta.env)
I'm struggling to get this to work as this file end up getting included in the client and the serverEnv parse produces and error. I'e tried a couple of things * splitting into different files - but it ends up being included anyway
export const serverEnv = createServerOnlyFn(() => schema.parse(process.env));
export const serverEnv = createServerOnlyFn(() => schema.parse(process.env));
But I feel like this will impact performance as throughout the code I'll be using serverEnv() everywhere so it's always reparsing. What's the "right" pattern here?
Environment Variables | TanStack Start React Docs
Learn how to securely configure and use environment variables in your TanStack Start application across different contexts (server functions, client code, and build processes). Quick Start TanStack St...
3 Replies
vicious-gold
vicious-gold11h ago
Try https://env.t3.gg It solves all of that
Env
Never build your apps with invalid environment variables again. Validate and transform your environment with the full power of Zod.
vicious-gold
vicious-gold11h ago
export const env = createEnv({
clientPrefix: "VITE_",
emptyStringAsUndefined: true,
server: {
DATABASE_URL: z.string().url(),
},
client: {
VITE_APP_URL: z.string().url(),
},
runtimeEnv: {
...process.env,
...import.meta.env,
},
})
export const env = createEnv({
clientPrefix: "VITE_",
emptyStringAsUndefined: true,
server: {
DATABASE_URL: z.string().url(),
},
client: {
VITE_APP_URL: z.string().url(),
},
runtimeEnv: {
...process.env,
...import.meta.env,
},
})
firm-tan
firm-tan8h ago
I am using createIsomorphicFn() for environment variables. So basically
const getEnv = createIsomorphicFn()
.client(() => publicEnvSchema.parse(import.meta.env))
.server(() => serverEnvSchema.parse(process.env))

export const env = getEnv();
const getEnv = createIsomorphicFn()
.client(() => publicEnvSchema.parse(import.meta.env))
.server(() => serverEnvSchema.parse(process.env))

export const env = getEnv();
So I am always using the correct environment no matter what. But this does need strict undefined/null handling though.

Did you find this page helpful?