Skip to content

Typed environments

Run envlet login, then run envlet types in a linked repository:

Terminal window
envlet types

The first run asks for a language and repository-relative output path. It records both under types in .envlet. Later runs use that configuration.

For this schema:

  • PORT: required integer
  • RATIO: optional number
  • ENABLED: required boolean
  • API_URL: required URL
  • SETTINGS: required JSON
  • MODE: enum with development and production

TypeScript output includes:

declare module "@envlet/sdk" {
interface Env {
API_URL: string;
ENABLED: boolean;
MODE: "development" | "production";
PORT: number;
RATIO?: number;
SETTINGS: unknown;
}
}

Python uses int, float, bool, str, Literal, Any, and Optional. Go uses int64, float64, bool, string, any for json, and pointers for optional values. Rust uses i64, f64, bool, String, envlet::serde_json::Value, and Option.

PHP uses int, float, bool, string, mixed, and nullable properties. Elixir uses integer(), float(), boolean(), String.t(), term(), and a nil union. Ruby writes the same Struct with a generated schema map. The generated loader reads the parsed values the SDK returns and checks each one against the declared type, so it needs no dependency beyond the SDK.

Commit the generated file and .envlet. Check for name or schema drift in CI:

- run: npx envlet types --check
env:
ENVLET_TOKEN: ${{ secrets.ENVLET_TOKEN }}

--check does not fetch values or write files. It exits with status 1 when a name, type, required setting, or enum set differs. Withheld names are reported but remain part of the environment schema.