Flat layout
Get the ultimate DX in Next.js using a single, unified flat schema file.
In this setup, you define all your environment variables in a single flat object.
To protect server-side secrets from ever reaching the client bundle, ArkEnv uses a proxy that throws a runtime error if a server-side variable is detected.
Server logic in client bundle
Defining your schemas together means the server validation logic is shipped in the client bundle.
| ⚠️ Visible in JS bundle | 🔒 Secure on server |
|---|---|
| Schema (keys, types, and constraints) e.g., DATABASE_URL: string.url | Runtime values e.g., "postgresql://db..." |
The values themselves are not shipped to the client! But if exposing your server variable names, types, or constraints is a security concern, use the strict layout instead.
Setup
The easiest way to bootstrap the flat layout is with the ArkEnv CLI. It automatically configures @arkenv/nextjs for your existing Next.js project and generates your env.ts file.
npx @arkenv/cli@latest initpnpm dlx @arkenv/cli@latest inityarn dlx @arkenv/cli@latest initbunx @arkenv/cli@latest initYour schema
When bootstrapping with the CLI, it generates a single env.ts file where you define your environment variables directly in a flat structure:
By default, ArkEnv for Next.js uses an automatic code generation wrapper (withArkEnv) in your Next.js config to build and inject the runtimeEnv block at compile time. This is why the schema file imports from @/generated/env.gen rather than @arkenv/nextjs directly. To opt out, simply import from @arkenv/nextjs directly and provide your own runtimeEnv mapping.
import from "@/generated/env.gen";
export const = ({
: "string",
: "string",
: "'development' | 'production' | 'test' = 'development'",
});Exposing client variables
By default, ArkEnv automatically identifies and exposes variables to the client based on two criteria:
- Keys prefixed with
NEXT_PUBLIC_(e.g.NEXT_PUBLIC_API_URL). - The
NODE_ENVvariable (which is implicitly shared to align with Next.js inlining).
If you have custom variables that do not follow the prefix convention but must be exposed to the client, you can specify them using the exposeToClient option:
import from "@/generated/env.gen";
export const = ({
: "string",
: "string",
: "string",
}, {
: ["CUSTOM_VAR"]
});