Hosting presets

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

Edit on GitHub

Vercel, Netlify, Cloudflare, and the other hosts inject system variables you would otherwise copy out of their docs. ArkEnv presets write those variables into your schema, pre-typed and optional, while you scaffold.

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

Presets write schema code

ArkEnv is code-first. A preset writes readable TypeScript into ./env.ts. Nothing loads that preset at runtime.

Select a preset during init

Pick the host while you scaffold. Those system variables land in the schema as optional, pre-typed fields. You can still paste them in later from the snippets below.

Select the provider in the wizard, or pass --preset:

npx arkenv init --preset vercel

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

The short form is -P. Passing none scaffolds standard schema templates without provider fields.

Adding presets to an existing schema

Init is not the only moment you can name a host. The snippets below are the same TypeScript the preset would have written. Paste them into an existing ./env.ts when the project is already running.

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?",
});

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?",
});

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?",
});

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?",
});

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?",
});

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?",
});

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
import arkenv from "@arkenv/core";

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 arkenv, { type } 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