Getting Started
This page walks you through installing @zap-studio/env and validating your first env object. For deeper details, check the other pages in this section.
Install
You also need a schema library that implements Standard Schema, such as Zod, Valibot, or ArkType.
Define a Schema
Split your vars into server (server-only) and client (readable everywhere, exposed to the browser). Use shared for vars that don't need the client/server split at all.
import { z } from "zod";
const schema = {
server: {
DATABASE_URL: z.string().url(),
},
client: {
NEXT_PUBLIC_API_URL: z.string().url(),
},
clientPrefix: "NEXT_PUBLIC_",
};clientPrefix is required as soon as client is declared — see server/client/shared for why.
Validate Your Env
Call createEnvironment(...) with the schema and the resolved env object to validate against.
import { createEnvironment } from "@zap-studio/env";
import { z } from "zod";
export const env = createEnvironment({
server: {
DATABASE_URL: z.string().url(),
},
client: {
NEXT_PUBLIC_API_URL: z.string().url(),
},
clientPrefix: "NEXT_PUBLIC_",
runtimeEnvStrict: {
DATABASE_URL: process.env.DATABASE_URL,
NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL,
},
});Each var is on its own line. Bundlers (webpack, Next.js, Vite) replace a literal process.env.X line at build time — they cannot do this with a spread of the whole object. This matters for client vars, since they must end up in the browser bundle. See Advanced Options for when runtimeEnv: process.env is fine instead.
If any declared var fails validation, createEnvironment throws an EnvironmentValidationError listing every invalid key.
Read Values
The returned env object is fully typed from your schemas. On the server, every declared var is readable. Off the server, reading a server-only key throws instead of silently returning undefined.
env.DATABASE_URL; // string — throws if read from a client bundle
env.NEXT_PUBLIC_API_URL; // string — readable everywhereisServer defaults to typeof window === "undefined". Set it yourself when that default is wrong, such as in some edge or SSR contexts — see server/client/shared.
Next Steps
server/client/shared— the full split,clientPrefix, and the access guardextends— reuse schemas across packages and apps- Presets — type vars your hosting platform already sets
generateEnvironmentExample— keep.env.examplein sync with your schema