Environment

Server code reads the environment with env() from @torpor/build/env. On Node it returns process.env, with .env files loaded in dev and preview; on Cloudflare it returns the platform environment, including bindings such as KV namespaces and D1 databases:

import env from "@torpor/build/env";

const { API_URL, DB } = env();

It is server-only: env() is available in load functions, actions, +server.ts endpoints and hooks, and it throws when called outside a request.

Typing the environment

Declare your app's keys in an ambient src/env.d.ts file:

/// <reference types="@torpor/build/env" />
declare global {
	interface TorporEnv {
		API_URL: string;
		JWT_SECRET: string;
		DB: D1Database;
	}
}

Adapter packages add their platform's keys the same way — the Cloudflare adapter declares the ASSETS binding, for example — and framework keys (all optional) are reserved by @torpor/build.

Validating the environment

Types can drift from reality: a key can be declared but never set. Add a Standard Schema (zod, valibot, arktype, etc) to site.env in your config file, and env() validates the environment on first use per request, throwing with the schema's issues instead of passing undefined along:

// site.config.ts
import { z } from "zod";
import { Site } from "@torpor/build";

const site = new Site();

site.env = z.object({
	API_URL: z.string().url(),
	JWT_SECRET: z.string(),
	DB: z.instanceof(D1Database),
});

export default site;

The schema must validate synchronously — zod, valibot and arktype all do. It also parses: whatever it returns (defaults, trimmed strings) is what env() gives back.