Next.js
The Next.js package comes preconfigured for Next.js and also enforces some extra rules by default to make sure you have out-of-the-box compatibility in all different Next.js runtimes.
Install dependencies
Install the required dependencies:
pnpm add @t3-oss/env-nextjs zod
pnpm add @t3-oss/env-nextjs zod
Create your schema
import { createEnv } from "@t3-oss/env-nextjs";
import { z } from "zod";
export const env = createEnv({
server: {
DATABASE_URL: z.string().url(),
OPEN_AI_API_KEY: z.string().min(1),
},
client: {
NEXT_PUBLIC_PUBLISHABLE_KEY: z.string().min(1),
},
runtimeEnv: {
DATABASE_URL: process.env.DATABASE_URL,
OPEN_AI_API_KEY: process.env.OPEN_AI_API_KEY,
NEXT_PUBLIC_PUBLISHABLE_KEY: process.env.NEXT_PUBLIC_PUBLISHABLE_KEY,
},
});
import { createEnv } from "@t3-oss/env-nextjs";
import { z } from "zod";
export const env = createEnv({
server: {
DATABASE_URL: z.string().url(),
OPEN_AI_API_KEY: z.string().min(1),
},
client: {
NEXT_PUBLIC_PUBLISHABLE_KEY: z.string().min(1),
},
runtimeEnv: {
DATABASE_URL: process.env.DATABASE_URL,
OPEN_AI_API_KEY: process.env.OPEN_AI_API_KEY,
NEXT_PUBLIC_PUBLISHABLE_KEY: process.env.NEXT_PUBLIC_PUBLISHABLE_KEY,
},
});
Unlike in the core package, runtimeEnv
is strict by default, meaning you'll have to destructure all the keys manually. This is due to how Next.js bundles environment variables and only explicitely accessed variables are included in the bundle. Missing keys will result in a type-error:
Validate schema on build (recommended)
We recommend you importing your newly created file in your next.config.mjs
. This will make sure your environment variables are validated at build time which will save you a lot of time and headaches down the road.
import "./src/env.mjs";
/** @type {import("next").NextConfig} */
const config = {
/** ... */
};
export default config;
import "./src/env.mjs";
/** @type {import("next").NextConfig} */
const config = {
/** ... */
};
export default config;
Use your schema
Then, import the env
object in your application and use it, taking advantage of type-safety and auto-completion:
import { env } from "~/env"; // On server
export const GET = async () => {
// do fancy ai stuff
const magic = await fetch("...", {
headers: { Authorization: env.OPEN_AI_API_KEY },
});
// ...
};
import { env } from "~/env"; // On server
export const GET = async () => {
// do fancy ai stuff
const magic = await fetch("...", {
headers: { Authorization: env.OPEN_AI_API_KEY },
});
// ...
};
import { env } from "~/env"; // On client - same import!
export const SomeComponent = () => {
return (
<SomeProvider publishableKey={env.PUBLIC_PUBLISHABLE_KEY}>
{/* ... */}
</SomeProvider>
);
};
import { env } from "~/env"; // On client - same import!
export const SomeComponent = () => {
return (
<SomeProvider publishableKey={env.PUBLIC_PUBLISHABLE_KEY}>
{/* ... */}
</SomeProvider>
);
};