Migrating from T3 Env
Replace createEnv and runtimeEnv with a flat ArkEnv schema.
T3 Env is a major inspiration for ArkEnv's Next.js security model. On
ArkEnv you drop the manual runtimeEnv map and keep a flat schema.
For a feature cheatsheet, see Why ArkEnv?.
What changes
The table below is the mapping you need while you edit files.
| Feature | T3 Env | ArkEnv |
|---|---|---|
| Core function | createEnv from @t3-oss/env-nextjs | arkenv from @arkenv/nextjs or @arkenv/core |
| Schema structure | Nested { server, client, runtimeEnv } | Flat schema (optional two-module recipe for name isolation) |
| Client inlining | Manual runtimeEnv object | withArkEnv writes the mapping |
| Validator | Zod only | ArkType via @arkenv/core, or Zod via @arkenv/standard |
A flat layout still infers types and throws if client code reads a server key. Use the two-module recipe when secret names must stay out of the client graph.
Next.js migration steps
Work through these steps on an existing Next.js app.
Install ArkEnv and remove T3 Env
ArkType:
npm install @arkenv/core @arkenv/nextjs arktype
npm rm @t3-oss/env-nextjspnpm add @arkenv/core @arkenv/nextjs arktype
pnpm remove @t3-oss/env-nextjsyarn add @arkenv/core @arkenv/nextjs arktype
yarn remove @t3-oss/env-nextjsbun install @arkenv/core @arkenv/nextjs arktype
bun remove @t3-oss/env-nextjsZod:
npm install @arkenv/standard @arkenv/nextjs zod
npm rm @t3-oss/env-nextjspnpm add @arkenv/standard @arkenv/nextjs zod
pnpm remove @t3-oss/env-nextjsyarn add @arkenv/standard @arkenv/nextjs zod
yarn remove @t3-oss/env-nextjsbun install @arkenv/standard @arkenv/nextjs zod
bun remove @t3-oss/env-nextjsWrap next.config.ts
import type { NextConfig } from "next";
import { } from "@arkenv/nextjs/config";
const : NextConfig = {};
export default ();Without ArkType, import withArkEnv from
@arkenv/nextjs/standard/config.
Replace createEnv with a flat schema
T3 Env:
import { createEnv } from "@t3-oss/env-nextjs";
import * as z from "zod";
export const env = createEnv({
server: {
DATABASE_URL: z.url(),
},
client: {
NEXT_PUBLIC_APP_URL: z.url(),
},
runtimeEnv: {
DATABASE_URL: process.env.DATABASE_URL,
NEXT_PUBLIC_APP_URL: process.env.NEXT_PUBLIC_APP_URL,
},
});ArkEnv (ArkType). withArkEnv generates .arkenv/env.gen.ts:
import from "@/.arkenv";
export const = ({
: "string.url",
: "string.url",
});ArkEnv (Zod):
import from "@/.arkenv";
import * as from "zod";
export const = ({
: .(),
: .(),
});You do not copy keys into runtimeEnv. NEXT_PUBLIC_ marks client
variables.
Retarget imports
Change import { env } from "~/env" (or src/env.js) to your new
./env module.
Optional: two-module recipe
If you used two createEnv calls in T3 Env for name/type isolation,
mirror that with two ArkEnv modules and two imports — not a CLI
--strict flag. See
Client vs. server.