Layouts

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.

env.ts

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 init
pnpm dlx @arkenv/cli@latest init
yarn dlx @arkenv/cli@latest init
bunx @arkenv/cli@latest init

Your 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.

src/env.ts
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:

  1. Keys prefixed with NEXT_PUBLIC_ (e.g. NEXT_PUBLIC_API_URL).
  2. The NODE_ENV variable (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:

src/env.ts
import  from "@/generated/env.gen";

export const  = ({
	: "string",
	: "string",
	: "string",
}, {
	: ["CUSTOM_VAR"]
});