🎉 Standard Schema support is here: Use ArkEnv with Zod, Valibot, and more!
ArkEnv

How to reuse your schema

Define your schema once and reuse it across your application.

ArkEnv supports both raw schema objects and type definitions created with ArkType's type() function. Use type definitions when you need to validate the same environment variables in multiple places.

Link to section: basic-usageBasic usage

Recall that with ArkEnv, defining your schema is done at the same time as you parse the environment variables:

import arkenv from 'arkenv';

const  = arkenv({
  HOST: "string.host",
  PORT: "number.port",
  DEBUG: "boolean",
});

But what if you wanted to share this schema across your app and validate+parse it against different environments?

This might sound like a niche use-case, but it comes up more often than you'd think - especially with tools like Vite, Next.js, or Bun, where multiple runtimes might need access to the same environment variables. Even in something as simple as a Vite+React setup, you might want your .env schema available both inside your vite.config.ts (Node.js) and in client code (Vite dev server). See the Node.js example for a basic setup, or the Vite playground for a complete multi-runtime configuration.

That's where type definitions start making sense: define your schema once with type(), and reuse it wherever you need.

import arkenv, { type } from 'arkenv';

const Env = type({
  HOST: "string.host",
  PORT: "number.port",
  DEBUG: "boolean",
});

// Use it in multiple places with full type inference
const env1 = arkenv(Env, process.env);
const env2 = arkenv(Env, { HOST: "localhost", PORT: "3000", DEBUG: "true" });

// TypeScript knows the exact types
const host: string = env1.HOST;
const port: number = env1.PORT;

Link to section: sharing-across-modulesSharing across modules

Export a type definition from one module and import it in others:

import { type } from 'arkenv';

export const Env = type({
  DATABASE_HOST: "string.host",
  DATABASE_PORT: "number.port",
  API_KEY: "string",
});
import arkenv from 'arkenv';
import { Env } from './env-schema';

export const dbEnv = arkenv(Env, process.env);
import arkenv from 'arkenv';
import { Env } from './env-schema';

export const apiEnv = arkenv(Env, process.env);

Link to section: type-inferenceType inference

Type definitions provide the same type safety as raw schema objects:

import arkenv, { type } from 'arkenv';

const Env = type({
  PORT: "number.port",
  HOST: "string.host",
  TIMEOUT: "number >= 0",
});

const env = arkenv(Env, process.env);

const port: number = env.PORT;
const host: string = env.HOST;
const timeout: number = env.TIMEOUT;

Link to section: different-environment-sourcesDifferent environment sources

Use the same schema with different environment sources:

import arkenv, { type } from 'arkenv';

const Env = type({
  API_URL: "string",
  API_KEY: "string",
});

const productionEnv = arkenv(Env, process.env);
const testEnv = arkenv(Env, {
  API_URL: "http://localhost:3000",
  API_KEY: "test-key",
});

Link to section: mixing-approachesMixing approaches

You can mix raw schema objects and type definitions in the same codebase:

import arkenv, { type } from 'arkenv';

// Raw schema object (simple, one-off)
const simpleEnv = arkenv({
  NODE_ENV: "'development' | 'production'",
});

// Type definition (reusable)
const complexSchema = type({
  DATABASE_HOST: "string.host",
  DATABASE_PORT: "number.port",
  DEBUG: "boolean",
});

const complexEnv = arkenv(complexSchema, process.env);

Both approaches provide the same validation and type safety. Use raw objects for simple, one-off schemas, and type definitions when you need to reuse the schema.

On this page