Hosting presets

Pre-populate schemas with Vercel, Netlify, Cloudflare, Railway, Render, or Fly.io environment variables.

Edit on GitHub

Hosting providers inject system environment variables at build and runtime. Presets teach ArkEnv which variables to generate into your schema, pre-typed and optional, so you do not have to look them up manually.

Presets work with ArkType, Zod, and Valibot on a flat env.ts schema.

[!NOTE] ArkEnv is code-first. Presets write readable TypeScript schema code directly into your ./env.ts. There are no runtime dependencies on CLI presets or black-box configuration loaders.

Select a preset during init

When bootstrapping a project, select your hosting provider from the interactive wizard or specify the --preset flag:

npx arkenv init --preset vercel
pnpm dlx arkenv init --preset vercel
yarn dlx arkenv init --preset vercel
bunx arkenv init --preset vercel

Accepted values: none, vercel, netlify, cloudflare, railway, render, fly.

The CLI also accepts -P, --host-preset, or -H as aliases. Passing none scaffolds standard schema templates without provider fields.

Adding presets to an existing schema

Because ArkEnv is code-first and generates plain TypeScript schemas, you can copy and paste hosting provider fields directly into your ./env.ts at any time.

Vercel

env.ts
import arkenv from "@arkenv/core";

export const env = arkenv({
  DATABASE_URL: "string",

  // Vercel system environment variables
  VERCEL: "string?",
  VERCEL_ENV: "'production' | 'preview' | 'development'?",
  VERCEL_URL: "string?",
});
env.ts
import arkenv from "@arkenv/standard";
import { z } from "zod";

export const env = arkenv({
  DATABASE_URL: z.string(),

  // Vercel system environment variables
  VERCEL: z.string().optional(),
  VERCEL_ENV: z.enum(["production", "preview", "development"]).optional(),
  VERCEL_URL: z.string().optional(),
});
env.ts
import arkenv from "@arkenv/standard";
import * as v from "valibot";

export const env = arkenv({
  DATABASE_URL: v.string(),

  // Vercel system environment variables
  VERCEL: v.optional(v.string()),
  VERCEL_ENV: v.optional(v.picklist(["production", "preview", "development"])),
  VERCEL_URL: v.optional(v.string()),
});

Netlify

env.ts
import arkenv from "@arkenv/core";

export const env = arkenv({
  DATABASE_URL: "string",

  // Netlify system environment variables
  NETLIFY: "string?",
  DEPLOY_URL: "string?",
  CONTEXT: "'production' | 'deploy-preview' | 'branch-deploy'?",
  URL: "string?",
});
env.ts
import arkenv from "@arkenv/standard";
import { z } from "zod";

export const env = arkenv({
  DATABASE_URL: z.string(),

  // Netlify system environment variables
  NETLIFY: z.string().optional(),
  DEPLOY_URL: z.string().optional(),
  CONTEXT: z.enum(["production", "deploy-preview", "branch-deploy"]).optional(),
  URL: z.string().optional(),
});
env.ts
import arkenv from "@arkenv/standard";
import * as v from "valibot";

export const env = arkenv({
  DATABASE_URL: v.string(),

  // Netlify system environment variables
  NETLIFY: v.optional(v.string()),
  DEPLOY_URL: v.optional(v.string()),
  CONTEXT: v.optional(v.picklist(["production", "deploy-preview", "branch-deploy"])),
  URL: v.optional(v.string()),
});

Cloudflare Pages / Workers

env.ts
import arkenv from "@arkenv/core";

export const env = arkenv({
  DATABASE_URL: "string",

  // Cloudflare system environment variables
  CF_PAGES: "string?",
  CF_PAGES_COMMIT_SHA: "string?",
  CF_PAGES_BRANCH: "string?",
  CF_PAGES_URL: "string?",
});
env.ts
import arkenv from "@arkenv/standard";
import { z } from "zod";

export const env = arkenv({
  DATABASE_URL: z.string(),

  // Cloudflare system environment variables
  CF_PAGES: z.string().optional(),
  CF_PAGES_COMMIT_SHA: z.string().optional(),
  CF_PAGES_BRANCH: z.string().optional(),
  CF_PAGES_URL: z.string().optional(),
});
env.ts
import arkenv from "@arkenv/standard";
import * as v from "valibot";

export const env = arkenv({
  DATABASE_URL: v.string(),

  // Cloudflare system environment variables
  CF_PAGES: v.optional(v.string()),
  CF_PAGES_COMMIT_SHA: v.optional(v.string()),
  CF_PAGES_BRANCH: v.optional(v.string()),
  CF_PAGES_URL: v.optional(v.string()),
});

Railway

env.ts
import arkenv from "@arkenv/core";

export const env = arkenv({
  DATABASE_URL: "string",

  // Railway system environment variables
  RAILWAY_ENVIRONMENT_NAME: "string?",
  RAILWAY_PUBLIC_DOMAIN: "string?",
  RAILWAY_SERVICE_NAME: "string?",
  RAILWAY_GIT_COMMIT_SHA: "string?",
});
env.ts
import arkenv from "@arkenv/standard";
import { z } from "zod";

export const env = arkenv({
  DATABASE_URL: z.string(),

  // Railway system environment variables
  RAILWAY_ENVIRONMENT_NAME: z.string().optional(),
  RAILWAY_PUBLIC_DOMAIN: z.string().optional(),
  RAILWAY_SERVICE_NAME: z.string().optional(),
  RAILWAY_GIT_COMMIT_SHA: z.string().optional(),
});
env.ts
import arkenv from "@arkenv/standard";
import * as v from "valibot";

export const env = arkenv({
  DATABASE_URL: v.string(),

  // Railway system environment variables
  RAILWAY_ENVIRONMENT_NAME: v.optional(v.string()),
  RAILWAY_PUBLIC_DOMAIN: v.optional(v.string()),
  RAILWAY_SERVICE_NAME: v.optional(v.string()),
  RAILWAY_GIT_COMMIT_SHA: v.optional(v.string()),
});

Render

env.ts
import arkenv from "@arkenv/core";

export const env = arkenv({
  DATABASE_URL: "string",

  // Render system environment variables
  RENDER: "string?",
  RENDER_SERVICE_ID: "string?",
  RENDER_SERVICE_TYPE: "string?",
  RENDER_EXTERNAL_URL: "string?",
});
env.ts
import arkenv from "@arkenv/standard";
import { z } from "zod";

export const env = arkenv({
  DATABASE_URL: z.string(),

  // Render system environment variables
  RENDER: z.string().optional(),
  RENDER_SERVICE_ID: z.string().optional(),
  RENDER_SERVICE_TYPE: z.string().optional(),
  RENDER_EXTERNAL_URL: z.string().optional(),
});
env.ts
import arkenv from "@arkenv/standard";
import * as v from "valibot";

export const env = arkenv({
  DATABASE_URL: v.string(),

  // Render system environment variables
  RENDER: v.optional(v.string()),
  RENDER_SERVICE_ID: v.optional(v.string()),
  RENDER_SERVICE_TYPE: v.optional(v.string()),
  RENDER_EXTERNAL_URL: v.optional(v.string()),
});

Fly.io

env.ts
import arkenv from "@arkenv/core";

export const env = arkenv({
  DATABASE_URL: "string",

  // Fly.io system environment variables
  FLY_APP_NAME: "string?",
  FLY_REGION: "string?",
  FLY_ALLOC_ID: "string?",
});
env.ts
import arkenv from "@arkenv/standard";
import { z } from "zod";

export const env = arkenv({
  DATABASE_URL: z.string(),

  // Fly.io system environment variables
  FLY_APP_NAME: z.string().optional(),
  FLY_REGION: z.string().optional(),
  FLY_ALLOC_ID: z.string().optional(),
});
env.ts
import arkenv from "@arkenv/standard";
import * as v from "valibot";

export const env = arkenv({
  DATABASE_URL: v.string(),

  // Fly.io system environment variables
  FLY_APP_NAME: v.optional(v.string()),
  FLY_REGION: v.optional(v.string()),
  FLY_ALLOC_ID: v.optional(v.string()),
});

Customizing and refining variables

Because ArkEnv gives full code ownership to your repository, you have complete control over how platform variables are validated:

Adding missing platform variables

If a hosting provider introduces a new environment variable, add the variable directly to your schema:

./env.ts
export const env = arkenv({
  DATABASE_URL: "string",

  // Add new or unlisted provider variables directly:
  VERCEL_NEW_FEATURE: "string?",
  VERCEL_ENV: "'production' | 'preview' | 'development'?",
  VERCEL_URL: "string?",
});

Refining types and transformations

You can modify field definitions to add stricter validations, regex constraints, default values, or runtime transformations (such as prefixing URLs with https://):

./env.ts
import { type } from "@arkenv/core";
import arkenv from "@arkenv/core";

export const env = arkenv({
  // Custom transformed Vercel URL
  VERCEL_URL: type("string?").pipe((url) => (url ? `https://${url}` : undefined)),

  // Stricter custom environment enum
  VERCEL_ENV: "'production' | 'preview' | 'development' | 'staging'?",
});

What each preset adds

Every preset field is optional (present only when deployed on that provider). Fields split into:

  • Server-only: Kept off the client bundle.
  • Client-exposed: Safe on the client; the CLI also generates a framework-prefixed copy when a client prefix applies (NEXT_PUBLIC_, NUXT_PUBLIC_, VITE_).

Vercel

VariableTypeExposure
VERCELstring (optional)Server-only
VERCEL_ENV"production" | "preview" | "development" (optional)Client-exposed
VERCEL_URLstring (optional)Client-exposed

Netlify

VariableTypeExposure
NETLIFYstring (optional)Server-only
DEPLOY_URLstring (optional)Server-only
CONTEXT"production" | "deploy-preview" | "branch-deploy" (optional)Client-exposed
URLstring (optional)Client-exposed

Cloudflare Pages/Workers

VariableTypeExposure
CF_PAGESstring (optional)Server-only
CF_PAGES_COMMIT_SHAstring (optional)Server-only
CF_PAGES_BRANCHstring (optional)Client-exposed
CF_PAGES_URLstring (optional)Client-exposed

Railway

VariableTypeExposure
RAILWAY_ENVIRONMENT_NAMEstring (optional)Server-only
RAILWAY_PUBLIC_DOMAINstring (optional)Server-only
RAILWAY_SERVICE_NAMEstring (optional)Server-only
RAILWAY_GIT_COMMIT_SHAstring (optional)Server-only

Render

VariableTypeExposure
RENDERstring (optional)Server-only
RENDER_SERVICE_IDstring (optional)Server-only
RENDER_SERVICE_TYPEstring (optional)Server-only
RENDER_EXTERNAL_URLstring (optional)Server-only

Fly.io

VariableTypeExposure
FLY_APP_NAMEstring (optional)Server-only
FLY_REGIONstring (optional)Server-only
FLY_ALLOC_IDstring (optional)Server-only

Next steps